Files
EventHubBack/test/unit/admin_handler_login_tests.erl
T

136 lines
4.3 KiB
Erlang
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-module(admin_handler_login_tests).
-include_lib("eunit/include/eunit.hrl").
-include("records.hrl").
-define(TABLES, [admin, admin_audit, auth_session, ticket]).
-define(EMAIL, <<"admin@test.local">>).
-define(PASSWORD, <<"SecretPass1!">>).
setup() ->
eh_test_support:start_mnesia(),
eh_test_support:ensure_tables(?TABLES),
eh_test_support:ensure_jwt(),
catch application:ensure_all_started(argon2),
catch ets:new(eventhub_counters, [named_table, public, set, {write_concurrency, true}]),
ok.
cleanup(_) ->
eh_test_support:unload_cowboy(),
eh_test_support:delete_tables(?TABLES),
eh_test_support:stop_mnesia(),
ok.
admin_login_test_() ->
{foreach, fun setup/0, fun cleanup/1, [
{"POST login success", fun test_login_ok/0},
{"POST login bad credentials", fun test_login_bad_credentials/0},
{"POST login insufficient permissions", fun test_login_forbidden_role/0},
{"POST login missing fields", fun test_login_missing_fields/0},
{"POST login missing body", fun test_login_missing_body/0},
{"POST login invalid JSON", fun test_login_invalid_json/0},
{"GET login method not allowed", fun test_login_wrong_method/0}
]}.
%% argon2 is a Rust NIF; rebar hooks only build it on unix. Skip hash-dependent
%% cases when the NIF is unavailable (common on Windows without cargo).
argon2_ready() ->
case catch argon2:hash(<<"probe">>) of
{ok, _} -> true;
_ -> false
end.
require_argon2(Fun) ->
case argon2_ready() of
true -> Fun();
false -> {skip, "argon2 NIF not available"}
end.
test_login_ok() ->
require_argon2(fun() ->
{ok, Admin} = core_admin:create(?EMAIL, ?PASSWORD, admin),
{Status, _, Body} = eh_test_support:call(admin_handler_login, #{
method => <<"POST">>,
path => <<"/v1/admin/login">>,
auth => none,
body => jsx:encode(#{<<"email">> => ?EMAIL, <<"password">> => ?PASSWORD})
}),
?assertEqual(200, Status),
Resp = jsx:decode(Body, [return_maps]),
?assert(is_map_key(<<"token">>, Resp)),
?assert(is_map_key(<<"refresh_token">>, Resp)),
User = maps:get(<<"user">>, Resp),
?assertEqual(Admin#admin.id, maps:get(<<"id">>, User)),
?assertEqual(?EMAIL, maps:get(<<"email">>, User)),
?assertEqual(<<"admin">>, maps:get(<<"role">>, User)),
Audits = core_admin_audit:list(),
?assert(length(Audits) >= 1)
end).
test_login_bad_credentials() ->
%% Unknown email does not need password verification.
{Status, _, Body} = eh_test_support:call(admin_handler_login, #{
method => <<"POST">>,
path => <<"/v1/admin/login">>,
auth => none,
body => jsx:encode(#{<<"email">> => <<"nobody@test.local">>, <<"password">> => <<"x">>})
}),
?assertEqual(401, Status),
#{<<"error">> := <<"invalid_credentials">>} = jsx:decode(Body, [return_maps]).
test_login_forbidden_role() ->
require_argon2(fun() ->
{ok, Hash} = logic_auth:hash_password(?PASSWORD),
eh_test_support:seed_admin(#{
id => <<"adm_guest">>,
email => <<"guest@test.local">>,
password_hash => Hash,
role => guest
}),
{Status, _, Body} = eh_test_support:call(admin_handler_login, #{
method => <<"POST">>,
path => <<"/v1/admin/login">>,
auth => none,
body => jsx:encode(#{
<<"email">> => <<"guest@test.local">>,
<<"password">> => ?PASSWORD
})
}),
?assertEqual(403, Status),
#{<<"error">> := <<"insufficient_permissions">>} = jsx:decode(Body, [return_maps])
end).
test_login_missing_fields() ->
{Status, _, _} = eh_test_support:call(admin_handler_login, #{
method => <<"POST">>,
path => <<"/v1/admin/login">>,
auth => none,
body => jsx:encode(#{<<"email">> => ?EMAIL})
}),
?assertEqual(400, Status).
test_login_missing_body() ->
{Status, _, _} = eh_test_support:call(admin_handler_login, #{
method => <<"POST">>,
path => <<"/v1/admin/login">>,
auth => none,
has_body => false
}),
?assertEqual(400, Status).
test_login_invalid_json() ->
{Status, _, _} = eh_test_support:call(admin_handler_login, #{
method => <<"POST">>,
path => <<"/v1/admin/login">>,
auth => none,
body => <<"not-json">>
}),
?assertEqual(400, Status).
test_login_wrong_method() ->
{Status, _, _} = eh_test_support:call(admin_handler_login, #{
method => <<"GET">>,
path => <<"/v1/admin/login">>,
auth => none
}),
?assertEqual(405, Status).