feat(auth_mongo): use `with_timeout` for `query`

This commit is contained in:
Thales Macedo Garitezi 2022-09-22 11:28:44 -03:00
parent 90995069c6
commit f94c5ee40a
2 changed files with 41 additions and 15 deletions

View File

@ -54,7 +54,7 @@ check(ClientInfo = #{password := Password}, AuthResult,
case query(Pool, Collection, maps:from_list(replvars(Selector, ClientInfo))) of
undefined -> ok;
{error, Reason} ->
?tp(emqx_auth_mongo_superuser_check_authn_error, #{error => Reason}),
?tp(emqx_auth_mongo_check_authn_error, #{error => Reason}),
?LOG(error, "[MongoDB] Can't connect to MongoDB server: ~0p", [Reason]),
{stop, AuthResult#{auth_result => not_authorized, anonymous => false}};
UserMap ->
@ -131,6 +131,7 @@ available(Pool, Collection, Query) ->
available(Pool, Collection, Query, Fun) ->
try Fun(Pool, Collection, Query) of
{error, Reason} ->
?tp(emqx_auth_mongo_available_error, #{error => Reason}),
?LOG(error, "[MongoDB] ~p availability test error: ~0p", [Collection, Reason]),
{error, Reason};
Error = #{<<"code">> := Code} ->
@ -195,12 +196,10 @@ connect(Opts) ->
mongo_api:connect(Type, Hosts, Options, WorkerOptions).
query(Pool, Collection, Selector) ->
try
ecpool:with_client(Pool, fun(Conn) -> mongo_api:find_one(Conn, Collection, Selector, #{}) end)
catch
Err:Reason ->
{error, {Err, Reason}}
end.
Timeout = timer:seconds(15),
with_timeout(Timeout, fun() ->
ecpool:with_client(Pool, fun(Conn) -> mongo_api:find_one(Conn, Collection, Selector, #{}) end)
end).
query_multi(Pool, Collection, SelectorList) ->
?tp(emqx_auth_mongo_query_multi_enter, #{}),

View File

@ -94,10 +94,11 @@ all() ->
| OtherTCs].
resilience_tests() ->
[ t_acl_superuser_no_connection
[ t_acl_superuser_timeout
, t_available_acl_query_no_connection
, t_available_acl_query_timeout
, t_authn_no_connection
, t_available_authn_query_timeout
, t_authn_timeout
, t_available
].
@ -183,7 +184,7 @@ end_per_testcase(t_authn_full_selector_variables, Config) ->
ok;
end_per_testcase(TestCase, Config)
when TestCase =:= t_available_acl_query_timeout;
TestCase =:= t_acl_superuser_no_connection;
TestCase =:= t_acl_superuser_timeout;
TestCase =:= t_authn_no_connection;
TestCase =:= t_available_acl_query_no_connection ->
ProxyHost = ?config(proxy_host, Config),
@ -441,10 +442,10 @@ t_is_superuser_undefined(_Config) ->
?assertNot(emqx_auth_mongo:is_superuser(Pool, SuperQuery, ClientInfo)),
ok.
t_authn_no_connection(Config) ->
t_authn_timeout(Config) ->
ProxyHost = ?config(proxy_host, Config),
ProxyPort = ?config(proxy_port, Config),
FailureType = down,
FailureType = timeout,
{ok, C} = emqtt:start_link([{clientid, <<"simpleClient">>},
{username, <<"plain">>},
{password, <<"plain">>}]),
@ -460,12 +461,38 @@ t_authn_no_connection(Config) ->
end,
fun(Trace) ->
%% fails with `{exit,{{{badmatch,{{error,closed},...'
?assertMatch([_], ?of_kind(emqx_auth_mongo_superuser_check_authn_error, Trace)),
?assertMatch([_], ?of_kind(emqx_auth_mongo_check_authn_error, Trace)),
ok
end),
ok.
%% tests query timeout failure
t_available_authn_query_timeout(Config) ->
ProxyHost = ?config(proxy_host, Config),
ProxyPort = ?config(proxy_port, Config),
FailureType = timeout,
SuperQuery = superquery(),
?check_trace(
#{timetrap => timer:seconds(60)},
try
enable_failure(FailureType, ProxyHost, ProxyPort),
Pool = ?APP,
%% query_multi returns an empty list even on failures.
?assertEqual({error, timeout}, emqx_auth_mongo:available(Pool, SuperQuery)),
ok
after
heal_failure(FailureType, ProxyHost, ProxyPort)
end,
fun(Trace) ->
?assertMatch(
[#{?snk_kind := emqx_auth_mongo_available_error , error := _}],
?of_kind(emqx_auth_mongo_available_error, Trace))
end),
ok.
%% tests query_multi failure
t_available_acl_query_no_connection(Config) ->
test_acl_query_failure(down, Config).
@ -488,10 +515,10 @@ t_query_multi_unknown_exception(_Config) ->
meck:unload(ecpool)
end.
t_acl_superuser_no_connection(Config) ->
t_acl_superuser_timeout(Config) ->
ProxyHost = ?config(proxy_host, Config),
ProxyPort = ?config(proxy_port, Config),
FailureType = down,
FailureType = timeout,
reload({auth_query, [{password_hash, plain}, {password_field, [<<"password">>]}]}),
{ok, C} = emqtt:start_link([{clientid, <<"simpleClient">>},
{username, <<"plain">>},