Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
chrzaszcz authored and Paweł Chrząszcz committed Sep 7, 2022
1 parent 95bf2d5 commit 87d040e
Show file tree
Hide file tree
Showing 19 changed files with 1,120 additions and 145 deletions.
33 changes: 18 additions & 15 deletions big_tests/tests/muc_http_api_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,8 @@ all() ->
{group, negative}].

groups() ->
G = [{positive, [parallel], success_response() ++ complex()},
{negative, [parallel], failure_response()}],
ct_helper:repeat_all_until_all_ok(G).
[{positive, [parallel], success_response() ++ complex()},
{negative, [parallel], failure_response()}].

success_response() ->
[
Expand Down Expand Up @@ -279,28 +278,25 @@ failed_invites(Config) ->
Name = set_up_room(Config, Alice),
BAlice = escalus_client:short_jid(Alice),
BBob = escalus_client:short_jid(Bob),
% non-existing room
% Invite to a non-existent room
{{<<"404">>, _}, <<"Room not found">>} = send_invite(<<"thisroomdoesnotexist">>, BAlice, BBob),
% invite with bad jid
{{<<"400">>, _}, <<"Invalid jid:", _/binary>>} = send_invite(Name, BAlice, <<"@badjid">>),
{{<<"400">>, _}, <<"Invalid jid:", _/binary>>} = send_invite(Name, <<"@badjid">>, BBob),
% Invite with a bad jid
{{<<"400">>, _}, <<"Invalid recipient JID">>} = send_invite(Name, BAlice, <<"@badjid">>),
{{<<"400">>, _}, <<"Invalid sender JID">>} = send_invite(Name, <<"@badjid">>, BBob),
ok
end).

failed_messages(Config) ->
escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
escalus:fresh_story(Config, [{alice, 1}], fun(Alice) ->
Name = set_up_room(Config, Alice),
% non-existing room
% Message to a non-existent room succeeds in the current implementation
BAlice = escalus_client:short_jid(Alice),
BBob = escalus_client:short_jid(Bob),
{{<<"404">>, _}, <<"Room not found">>} = send_invite(<<"thisroomdoesnotexist">>, BAlice, BBob),
% invite with bad jid
{{<<"400">>, _}, <<"Invalid jid:", _/binary>>} = send_invite(Name, BAlice, <<"@badjid">>),
{{<<"400">>, _}, <<"Invalid jid:", _/binary>>} = send_invite(Name, <<"@badjid">>, BBob),
{{<<"204">>, _}, <<>>} = send_message(<<"thisroomdoesnotexist">>, BAlice),
% Message from a bad jid
{{<<"400">>, _}, <<"Invalid sender JID", _/binary>>} = send_message(Name, <<"@badjid">>),
ok
end).


%%--------------------------------------------------------------------
%% Ancillary (adapted from the MUC suite)
%%--------------------------------------------------------------------
Expand All @@ -324,6 +320,13 @@ send_invite(RoomName, BinFrom, BinTo) ->
reason => Reason},
rest_helper:post(admin, Path, Body).

send_message(RoomName, BinFrom) ->
Path = path([RoomName, "messages"]),
Message = <<"Greetings!">>,
Body = #{from => BinFrom,
body => Message},
rest_helper:post(admin, Path, Body).

make_distinct_name(Prefix) ->
{_, S, US} = os:timestamp(),
L = lists:flatten([integer_to_list(S rem 100), ".", integer_to_list(US)]),
Expand Down
137 changes: 20 additions & 117 deletions big_tests/tests/rest_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
-compile([export_all, nowarn_export_all]).

-include_lib("escalus/include/escalus.hrl").
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
-include_lib("exml/include/exml.hrl").

Expand All @@ -38,7 +37,6 @@
-define(OK, {<<"200">>, <<"OK">>}).
-define(CREATED, {<<"201">>, <<"Created">>}).
-define(NOCONTENT, {<<"204">>, <<"No Content">>}).
-define(ERROR, {<<"500">>, _}).
-define(NOT_FOUND, {<<"404">>, _}).
-define(NOT_AUTHORIZED, {<<"401">>, _}).
-define(FORBIDDEN, {<<"403">>, _}).
Expand All @@ -48,13 +46,9 @@
%% Suite configuration
%%--------------------------------------------------------------------

-define(REGISTRATION_TIMEOUT, 2). %% seconds
-define(ATOMS, [name, desc, category, action, security_policy, args, result, sender]).

all() ->
[
{group, admin},
{group, dynamic_module},
{group, auth},
{group, blank_auth},
{group, roster}
Expand All @@ -67,8 +61,8 @@ groups() ->
{roster, [parallel], [list_contacts,
befriend_and_alienate,
befriend_and_alienate_auto,
invalid_roster_operations]},
{dynamic_module, [], [stop_start_command_module]}].
invalid_roster_operations]}
].

auth_test_cases() ->
[auth_passes_correct_creds,
Expand All @@ -78,8 +72,7 @@ blank_auth_testcases() ->
[auth_always_passes_blank_creds].

test_cases() ->
[commands_are_listed,
non_existent_command_returns404,
[non_existent_command_returns404,
existent_command_with_missing_arguments_returns404,
user_can_be_registered_and_removed,
sessions_are_listed,
Expand All @@ -89,8 +82,7 @@ test_cases() ->
stanzas_are_sent_and_received,
messages_are_archived,
messages_can_be_paginated,
password_can_be_changed,
types_are_checked_separately_for_args_and_return
password_can_be_changed
].

suite() ->
Expand Down Expand Up @@ -125,99 +117,36 @@ end_per_group(auth, _Config) ->
end_per_group(_GroupName, Config) ->
escalus:delete_users(Config, escalus:get_users([alice, bob, mike])).

init_per_testcase(types_are_checked_separately_for_args_and_return = CaseName, Config) ->
{Mod, Code} = rpc(dynamic_compile, from_string, [custom_module_code()]),
rpc(code, load_binary, [Mod, "mod_commands_test.erl", Code]),
Config1 = dynamic_modules:save_modules(host_type(), Config),
dynamic_modules:ensure_modules(host_type(), [{mod_commands_test, []}]),
escalus:init_per_testcase(CaseName, Config1);
init_per_testcase(CaseName, Config) ->
MAMTestCases = [messages_are_archived, messages_can_be_paginated],
rest_helper:maybe_skip_mam_test_cases(CaseName, MAMTestCases, Config).

end_per_testcase(types_are_checked_separately_for_args_and_return = CaseName, Config) ->
dynamic_modules:restore_modules(Config),
escalus:end_per_testcase(CaseName, Config);
end_per_testcase(CaseName, Config) ->
escalus:end_per_testcase(CaseName, Config).

rpc(M, F, A) ->
distributed_helper:rpc(distributed_helper:mim(), M, F, A).

custom_module_code() ->
"-module(mod_commands_test).
-export([start/0, stop/0, start/2, stop/1, test_arg/1, test_return/1, supported_features/0]).
start() -> mongoose_commands:register(commands()).
stop() -> mongoose_commands:unregister(commands()).
start(_,_) -> start().
stop(_) -> stop().
supported_features() -> [dynamic_domains].
commands() ->
[
[
{name, test_arg},
{category, <<\"test_arg\">>},
{desc, <<\"List test_arg\">>},
{module, mod_commands_test},
{function, test_arg},
{action, create},
{args, [{arg, boolean}]},
{result, [{msg, binary}]}
],
[
{name, test_return},
{category, <<\"test_return\">>},
{desc, <<\"List test_return\">>},
{module, mod_commands_test},
{function, test_return},
{action, create},
{args, [{arg, boolean}]},
{result, {msg, binary}}
]
].
test_arg(_) -> <<\"bleble\">>.
test_return(_) -> ok.
"
.

%%--------------------------------------------------------------------
%% Tests
%%--------------------------------------------------------------------

% Authorization
auth_passes_correct_creds(_Config) ->
% try to login with the same creds
{?OK, _Lcmds} = gett(admin, <<"/commands">>, {<<"ala">>, <<"makota">>}).
{?OK, _Users} = gett(admin, path("users", [domain()]), {<<"ala">>, <<"makota">>}).

auth_fails_incorrect_creds(_Config) ->
% try to login with different creds
{?NOT_AUTHORIZED, _} = gett(admin, <<"/commands">>, {<<"ola">>, <<"mapsa">>}).
{?NOT_AUTHORIZED, _} = gett(admin, path("users", [domain()]), {<<"ola">>, <<"mapsa">>}).

auth_always_passes_blank_creds(_Config) ->
% we set control creds for blank
rest_helper:change_admin_creds(any),
% try with any auth
{?OK, Lcmds} = gett(admin, <<"/commands">>, {<<"aaaa">>, <<"bbbb">>}),
{?OK, Users} = gett(admin, path("users", [domain()]), {<<"aaaa">>, <<"bbbb">>}),
% try with no auth
{?OK, Lcmds} = gett(admin, <<"/commands">>).

commands_are_listed(_C) ->
{?OK, Lcmds} = gett(admin, <<"/commands">>),
DecCmds = decode_maplist(Lcmds),
ListCmd = #{action => <<"read">>, method => <<"GET">>, args => #{},
category => <<"commands">>,
desc => <<"List commands">>,
name => <<"list_methods">>,
path => <<"/commands">>},
%% Check that path and args are listed using a command with args
RosterCmd = #{action => <<"read">>, method => <<"GET">>,
args => #{caller => <<"string">>},
category => <<"contacts">>,
desc => <<"Get roster">>,
name => <<"list_contacts">>,
path => <<"/contacts/:caller">>},
?assertEqual([ListCmd], assert_inlist(#{name => <<"list_methods">>}, DecCmds)),
?assertEqual([RosterCmd], assert_inlist(#{name => <<"list_contacts">>}, DecCmds)).
{?OK, Users} = gett(admin, path("users", [domain()])).

non_existent_command_returns404(_C) ->
{?NOT_FOUND, _} = gett(admin, <<"/isitthereornot">>).
Expand Down Expand Up @@ -286,8 +215,8 @@ messages_error_handling(Config) ->
escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
AliceJID = escalus_utils:jid_to_lower(escalus_client:short_jid(Alice)),
BobJID = escalus_utils:jid_to_lower(escalus_client:short_jid(Bob)),
{{<<"400">>, _}, <<"Invalid jid:", _/binary>>} = send_message_bin(AliceJID, <<"@noway">>),
{{<<"400">>, _}, <<"Invalid jid:", _/binary>>} = send_message_bin(<<"@noway">>, BobJID),
{{<<"400">>, _}, <<"Invalid recipient JID">>} = send_message_bin(AliceJID, <<"@noway">>),
{{<<"400">>, _}, <<"Invalid sender JID">>} = send_message_bin(<<"@noway">>, BobJID),
ok
end).

Expand All @@ -299,9 +228,9 @@ stanzas_are_sent_and_received(Config) ->
?assertEqual(<<"attribute">>, exml_query:attr(Res, <<"extra">>)),
?assertEqual(<<"inside the sibling">>, exml_query:path(Res, [{element, <<"sibling">>}, cdata])),
Res1 = send_flawed_stanza(missing_attribute, Alice, Bob),
{?BAD_REQUEST, <<"both from and to are required">>} = Res1,
{?BAD_REQUEST, <<"Missing recipient JID">>} = Res1,
Res2 = send_flawed_stanza(malformed_xml, Alice, Bob),
{?BAD_REQUEST, <<"Malformed stanza: \"expected >\"">>} = Res2,
{?BAD_REQUEST, <<"Malformed stanza">>} = Res2,
ok
end).

Expand Down Expand Up @@ -537,50 +466,38 @@ invalid_roster_operations(Config) ->
BobS = binary_to_list(BobJID),
AlicePath = lists:flatten(["/contacts/", AliceS]),
% adds them to rosters
{?BAD_REQUEST, <<"Invalid jid", _/binary>>} = post(admin, AlicePath, #{jid => <<"@invalidjid">>}),
{?BAD_REQUEST, <<"Invalid jid", _/binary>>} = post(admin, "/contacts/@invalid_jid", #{jid => BobJID}),
{?BAD_REQUEST, <<"Invalid JID">>} = post(admin, AlicePath, #{jid => <<"@invalidjid">>}),
{?BAD_REQUEST, <<"Invalid user JID">>} = post(admin, "/contacts/@invalid_jid", #{jid => BobJID}),
% it is idempotent
{?NOCONTENT, _} = post(admin, AlicePath, #{jid => BobJID}),
{?NOCONTENT, _} = post(admin, AlicePath, #{jid => BobJID}),
PutPathA = lists:flatten([AlicePath, "/@invalid_jid"]),
{?BAD_REQUEST, <<"Invalid jid", _/binary>>} = putt(admin, PutPathA, #{action => <<"subscribe">>}),
{?BAD_REQUEST, <<"Invalid contact JID">>} = putt(admin, PutPathA, #{action => <<"subscribe">>}),
PutPathB = lists:flatten(["/contacts/@invalid_jid/", BobS]),
{?BAD_REQUEST, <<"Invalid jid", _/binary>>} = putt(admin, PutPathB, #{action => <<"subscribe">>}),
{?BAD_REQUEST, <<"Invalid user JID">>} = putt(admin, PutPathB, #{action => <<"subscribe">>}),
PutPathC = lists:flatten([AlicePath, "/", BobS]),
{?BAD_REQUEST, <<"invalid action">>} = putt(admin, PutPathC, #{action => <<"something stupid">>}),
{?BAD_REQUEST, <<"Invalid action">>} = putt(admin, PutPathC, #{action => <<"something stupid">>}),
ManagePath = lists:flatten(["/contacts/",
AliceS,
"/",
BobS,
"/manage"
]),
{?BAD_REQUEST, <<"invalid action">>} = putt(admin, ManagePath, #{action => <<"off with his head">>}),
{?BAD_REQUEST, <<"Invalid action">>} = putt(admin, ManagePath, #{action => <<"off with his head">>}),
MangePathA = lists:flatten(["/contacts/",
"@invalid",
"/",
BobS,
"/manage"
]),
{?BAD_REQUEST, <<"Invalid jid", _/binary>>} = putt(admin, MangePathA, #{action => <<"connect">>}),
{?BAD_REQUEST, <<"Invalid user JID">>} = putt(admin, MangePathA, #{action => <<"connect">>}),
MangePathB = lists:flatten(["/contacts/",
AliceS,
"/",
"@bzzz",
"/manage"
]),
{?BAD_REQUEST, <<"Invalid jid", _/binary>>} = putt(admin, MangePathB, #{action => <<"connect">>}),
ok
end
).

types_are_checked_separately_for_args_and_return(Config) ->
escalus:story(
Config, [{alice, 1}],
fun(_Alice) ->
% argument doesn't pass typecheck
{?BAD_REQUEST, _} = post(admin, "/test_arg", #{arg => 1}),
% return value doesn't pass typecheck
{?ERROR, _} = post(admin, "/test_return", #{arg => true}),
{?BAD_REQUEST, <<"Invalid contact JID">>} = putt(admin, MangePathB, #{action => <<"connect">>}),
ok
end
).
Expand Down Expand Up @@ -665,20 +582,6 @@ get_messages(Me, Other, Before, Count) ->
{?OK, Msgs} = gett(admin, GetPath),
Msgs.

stop_start_command_module(_) ->
%% Precondition: module responsible for resource is started. If we
%% stop the module responsible for this resource then the same
%% test will fail. If we start the module responsible for this
%% resource then the same test will succeed. With the precondition
%% described above we test both transition from `started' to
%% `stopped' and from `stopped' to `started'.
{?OK, _} = gett(admin, <<"/commands">>),
{stopped, _} = dynamic_modules:stop(host_type(), mod_commands),
{?NOT_FOUND, _} = gett(admin, <<"/commands">>),
{started, _} = dynamic_modules:start(host_type(), mod_commands, []),
timer:sleep(200), %% give the server some time to build the paths again
{?OK, _} = gett(admin, <<"/commands">>).

to_list(V) when is_binary(V) ->
binary_to_list(V);
to_list(V) when is_list(V) ->
Expand Down
4 changes: 2 additions & 2 deletions big_tests/tests/rest_helper.erl
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ insert_creds(Opts = #{handlers := Handlers}, Creds) ->
NewHandlers = [inject_creds_to_opts(Handler, Creds) || Handler <- Handlers],
Opts#{handlers := NewHandlers}.

inject_creds_to_opts(Handler = #{module := mongoose_api_admin}, Creds) ->
inject_creds_to_opts(Handler = #{module := mongoose_admin_api}, Creds) ->
case Creds of
{UserName, Password} ->
Handler#{username => UserName, password => Password};
Expand All @@ -277,7 +277,7 @@ is_roles_config(#{module := ejabberd_cowboy, handlers := Handlers}, Role) ->
lists:any(fun(#{module := Module}) -> Module =:= RoleModule end, Handlers);
is_roles_config(_, _) -> false.

role_to_module(admin) -> mongoose_api_admin;
role_to_module(admin) -> mongoose_admin_api;
role_to_module(client) -> mongoose_client_api.

mapfromlist(L) ->
Expand Down
2 changes: 1 addition & 1 deletion rel/files/mongooseim.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
transport.num_acceptors = 10
transport.max_connections = 1024

[[listen.http.handlers.mongoose_api_admin]]
[[listen.http.handlers.mongoose_admin_api]]
host = "localhost"
path = "/api"

Expand Down
6 changes: 3 additions & 3 deletions src/inbox/mod_inbox_api.erl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
{user_does_not_exist, io_lib:format("User ~s@~s does not exist", [User, Server])}).

-spec flush_user_bin(jid:jid(), Days :: integer()) ->
{ok, integer()} | {domain_not_found, binary()}.
{ok, integer()} | {domain_not_found | user_does_not_exist, binary()}.
flush_user_bin(#jid{luser = LU, lserver = LS} = JID, Days) ->
case mongoose_domain_api:get_host_type(LS) of
{ok, HostType} ->
Expand All @@ -33,7 +33,7 @@ flush_user_bin(#jid{luser = LU, lserver = LS} = JID, Days) ->
flush_domain_bin(Domain, Days) ->
LDomain = jid:nodeprep(Domain),
case mongoose_domain_api:get_host_type(LDomain) of
{ok, HostType} ->
{ok, HostType} ->
FromTS = days_to_timestamp(Days),
Count = mod_inbox_backend:empty_domain_bin(HostType, Domain, FromTS),
{ok, Count};
Expand All @@ -45,7 +45,7 @@ flush_domain_bin(Domain, Days) ->
{ok, integer()} | {host_type_not_found, binary()}.
flush_global_bin(HostType, Days) ->
case validate_host_type(HostType) of
ok ->
ok ->
FromTS = days_to_timestamp(Days),
Count = mod_inbox_backend:empty_global_bin(HostType, FromTS),
{ok, Count};
Expand Down
2 changes: 1 addition & 1 deletion src/mod_muc_api.erl
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ room_desc_to_map(Desc) ->
#{title => Title, private => Private, users_number => Number}
end.

-spec verify_room(jid:jid(), jid:jid()) -> ok | {internal | not_found, term()}.
-spec verify_room(jid:jid(), jid:jid()) -> ok | {internal | room_not_found, term()}.
verify_room(BareRoomJID, OwnerJID) ->
case mod_muc_room:can_access_room(BareRoomJID, OwnerJID) of
{ok, true} ->
Expand Down
Loading

0 comments on commit 87d040e

Please sign in to comment.