Skip to content

Commit

Permalink
Refactor code related to the @use directive
Browse files Browse the repository at this point in the history
  • Loading branch information
jacekwegr committed Dec 22, 2023
1 parent 6b45de0 commit 0ff0376
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 100 deletions.
14 changes: 7 additions & 7 deletions big_tests/tests/graphql_cets_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ init_per_suite(Config) ->
end.

end_per_suite(Config) ->
case rpc_call(mongoose_config, get_opt, [[internal_databases, cets, backend], undefined]) of
rdbms ->
case rpc_call(mongoose_config, lookup_opt, [[internal_databases, cets, backend]]) of
{ok, rdbms} ->
ensure_bad_node_unregistered(),
escalus:end_per_suite(Config);
_ ->
Expand All @@ -74,10 +74,10 @@ init_per_group(domain_admin_cets, Config) ->
Config1 = graphql_helper:init_domain_admin_handler(Config),
skip_if_cets_not_configured(Config1);
init_per_group(cets_not_configured, Config) ->
case rpc_call(mongoose_config, get_opt, [[internal_databases, cets], undefined]) of
undefined ->
case rpc_call(mongoose_config, lookup_opt, [[internal_databases, cets]]) of
{error, not_found} ->
graphql_helper:init_admin_handler(Config);
_ ->
{ok, _} ->
{skip, "CETS is configured"}
end.

Expand All @@ -88,8 +88,8 @@ end_per_group(_, _Config) ->
escalus_fresh:clean().

skip_if_cets_not_configured(Config) ->
case rpc_call(mongoose_config, get_opt, [[internal_databases, cets, backend], undefined]) of
rdbms ->
case rpc_call(mongoose_config, lookup_opt, [[internal_databases, cets, backend]]) of
{ok, rdbms} ->
Config;
_ ->
{skip, "CETS is not configured with RDBMS"}
Expand Down
12 changes: 6 additions & 6 deletions big_tests/tests/graphql_mnesia_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -99,21 +99,21 @@ init_per_group(domain_admin_mnesia, Config) ->
Config1 = graphql_helper:init_domain_admin_handler(Config),
skip_if_mnesia_not_configured(Config1);
init_per_group(mnesia_not_configured, Config) ->
case rpc_call(mongoose_config, get_opt, [[internal_databases, mnesia], undefined]) of
undefined ->
case rpc_call(mongoose_config, lookup_opt, [[internal_databases, mnesia]]) of
{error, not_found} ->
graphql_helper:init_admin_handler(Config);
_ ->
{ok, _} ->
{skip, "Mnesia is configured"}
end.
end_per_group(_, _Config) ->
graphql_helper:clean(),
escalus_fresh:clean().

skip_if_mnesia_not_configured(Config) ->
case rpc_call(mongoose_config, get_opt, [[internal_databases, mnesia], undefined]) of
undefined ->
case rpc_call(mongoose_config, lookup_opt, [[internal_databases, mnesia]]) of
{error, not_found} ->
{skip, "Mnesia is not configured"};
_ ->
{ok, _} ->
Config
end.

Expand Down
72 changes: 38 additions & 34 deletions src/graphql/directive/mongoose_graphql_directive_use.erl
Original file line number Diff line number Diff line change
Expand Up @@ -45,21 +45,23 @@
internal_databases := [binary()],
arg => binary(),
atom => term()}.
-type dependency_type() :: internal_databases | modules | services.
-type dependency_name() :: binary().

%% @doc Check the collected modules and services and swap the field resolver if any of them
%% is not loaded. The new field resolver returns the error that some modules or services
%% are not loaded.
handle_directive(#directive{id = <<"use">>, args = Args}, #schema_field{} = Field, Ctx) ->
#{modules := Modules, services := Services, internal_databases := DB} =

Check warning on line 55 in src/graphql/directive/mongoose_graphql_directive_use.erl

View check run for this annotation

Codecov / codecov/patch

src/graphql/directive/mongoose_graphql_directive_use.erl#L55

Added line #L55 was not covered by tests
UseCtx = aggregate_use_ctx(Args, Ctx),
UnloadedServices = filter_unloaded_services(Services),
UnloadedModules = filter_unloaded_modules(UseCtx, Ctx, Modules),
UnloadedDBs = filter_unloaded_db(DB),
case {UnloadedModules, UnloadedServices, UnloadedDBs} of
{[], [], []} ->
Items = [{modules, filter_unloaded_modules(UseCtx, Ctx, Modules)},

Check warning on line 57 in src/graphql/directive/mongoose_graphql_directive_use.erl

View check run for this annotation

Codecov / codecov/patch

src/graphql/directive/mongoose_graphql_directive_use.erl#L57

Added line #L57 was not covered by tests
{services, filter_unloaded_services(Services)},
{internal_databases, filter_unloaded_db(DB)}],
case lists:filter(fun({_, Names}) -> Names =/= [] end, Items) of

Check warning on line 60 in src/graphql/directive/mongoose_graphql_directive_use.erl

View check run for this annotation

Codecov / codecov/patch

src/graphql/directive/mongoose_graphql_directive_use.erl#L60

Added line #L60 was not covered by tests
[] ->
Field;
{_, _, _} ->
Fun = resolve_not_loaded_fun(UnloadedModules, UnloadedServices, UnloadedDBs),
NotLoaded ->
Fun = resolve_not_loaded_fun(NotLoaded),

Check warning on line 64 in src/graphql/directive/mongoose_graphql_directive_use.erl

View check run for this annotation

Codecov / codecov/patch

src/graphql/directive/mongoose_graphql_directive_use.erl#L64

Added line #L64 was not covered by tests
Field#schema_field{resolve = Fun}
end.

Expand All @@ -80,14 +82,14 @@ get_arg_value(_UseCtx, #{admin := #jid{lserver = Domain}}) ->

-spec aggregate_use_ctx(list(), ctx()) -> use_ctx().
aggregate_use_ctx(Args, #{use_dir := #{modules := Modules0, services := Services0,
internal_databases := DB0}}) ->
#{modules := Modules, services := Services, internal_databases := DB} =
internal_databases := Databases0}}) ->
#{modules := Modules, services := Services, internal_databases := Databases} =

Check warning on line 86 in src/graphql/directive/mongoose_graphql_directive_use.erl

View check run for this annotation

Codecov / codecov/patch

src/graphql/directive/mongoose_graphql_directive_use.erl#L86

Added line #L86 was not covered by tests
UseCtx = prepare_use_dir_args(Args),
UpdatedModules = Modules0 ++ Modules,
UpdatedServices = Services0 ++ Services,
UpdatedDB = DB0 ++ DB,
UpdatedDatabases = Databases0 ++ Databases,
UseCtx#{modules => UpdatedModules, services => UpdatedServices,

Check warning on line 91 in src/graphql/directive/mongoose_graphql_directive_use.erl

View check run for this annotation

Codecov / codecov/patch

src/graphql/directive/mongoose_graphql_directive_use.erl#L88-L91

Added lines #L88 - L91 were not covered by tests
internal_databases => UpdatedDB};
internal_databases => UpdatedDatabases};
aggregate_use_ctx(Args, _Ctx) ->
prepare_use_dir_args(Args).

Expand Down Expand Up @@ -139,28 +141,30 @@ filter_unloaded_services(Services) ->

-spec filter_unloaded_db([binary()]) -> [binary()].
filter_unloaded_db(DBs) ->
lists:filter(fun(DB) ->
mongoose_config:get_opt([internal_databases,
binary_to_existing_atom(DB)], undefined) == undefined
end, DBs).

-spec resolve_not_loaded_fun([binary()], [binary()], [binary()]) -> resolver().
resolve_not_loaded_fun(Modules, Services, Databases) ->
NotLoadedDescs = lists:filtermap(
fun
({[], _}) -> false;
({List, Desc}) when List =/= [] -> {true, Desc}
end,
[{Modules, "modules"}, {Services, "services"}, {Databases, "internal databases"}]
),
lists:filter(fun(DB) -> is_database_unloaded(DB) end, DBs).

Check warning on line 144 in src/graphql/directive/mongoose_graphql_directive_use.erl

View check run for this annotation

Codecov / codecov/patch

src/graphql/directive/mongoose_graphql_directive_use.erl#L144

Added line #L144 was not covered by tests

-spec is_database_unloaded(binary()) -> boolean().
is_database_unloaded(DB) ->
mongoose_config:lookup_opt([internal_databases,
binary_to_existing_atom(DB)]) == {error, not_found}.

Check warning on line 149 in src/graphql/directive/mongoose_graphql_directive_use.erl

View check run for this annotation

Codecov / codecov/patch

src/graphql/directive/mongoose_graphql_directive_use.erl#L149

Added line #L149 was not covered by tests

-spec resolve_not_loaded_fun([{dependency_type(), [dependency_name()]}]) -> resolver().
resolve_not_loaded_fun(NotLoaded) ->
Msg = not_loaded_message(NotLoaded),
Extra = maps:from_list([{error_key(Type), Names} || {Type, Names} <- NotLoaded]),

Check warning on line 154 in src/graphql/directive/mongoose_graphql_directive_use.erl

View check run for this annotation

Codecov / codecov/patch

src/graphql/directive/mongoose_graphql_directive_use.erl#L153-L154

Added lines #L153 - L154 were not covered by tests
fun(_, _, _, _) -> mongoose_graphql_helper:make_error(deps_not_loaded, Msg, Extra) end.

-spec not_loaded_message([{dependency_type(), [dependency_name()]}]) -> binary().
not_loaded_message(NotLoaded) ->
MsgPrefix = <<"Some of the required ">>,
MsgList = string:join(NotLoadedDescs, " and "),
MsgList = string:join([dependency_type_to_string(Item) || {Item, _} <- NotLoaded], " and "),
MsgBinaryList = list_to_binary(MsgList),
Msg = <<MsgPrefix/binary, MsgBinaryList/binary, " are not loaded">>,
Extra = maps:from_list(
[{list_to_atom("not_loaded_" ++
unicode:characters_to_list(string:replace(Desc, " ", "_"))), List} ||
{List, Desc} <- [{Modules, "modules"}, {Services, "services"},
{Databases, "internal databases"}],
lists:member(Desc, NotLoadedDescs)]),
fun(_, _, _, _) -> mongoose_graphql_helper:make_error(deps_not_loaded, Msg, Extra) end.
<<MsgPrefix/binary, MsgBinaryList/binary, " are not loaded">>.

Check warning on line 162 in src/graphql/directive/mongoose_graphql_directive_use.erl

View check run for this annotation

Codecov / codecov/patch

src/graphql/directive/mongoose_graphql_directive_use.erl#L159-L162

Added lines #L159 - L162 were not covered by tests

-spec dependency_type_to_string(dependency_type()) -> [string()].
dependency_type_to_string(Type) ->
string:replace(atom_to_list(Type), "_", " ").

Check warning on line 166 in src/graphql/directive/mongoose_graphql_directive_use.erl

View check run for this annotation

Codecov / codecov/patch

src/graphql/directive/mongoose_graphql_directive_use.erl#L166

Added line #L166 was not covered by tests

-spec error_key(dependency_type()) -> atom().
error_key(Type) ->
list_to_atom("not_loaded_" ++ atom_to_list(Type)).

Check warning on line 170 in src/graphql/directive/mongoose_graphql_directive_use.erl

View check run for this annotation

Codecov / codecov/patch

src/graphql/directive/mongoose_graphql_directive_use.erl#L170

Added line #L170 was not covered by tests
81 changes: 28 additions & 53 deletions test/mongoose_graphql_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ init_per_group(domain_permissions, Config) ->
[{domains, Domains} | Config];
init_per_group(use_directive, Config) ->
Config1 = meck_domain_api(Config),
mongoose_config:set_opts(#{internal_databases => #{db_a => #{}}}),
meck_module_and_service_checking(Config1);
init_per_group(_G, Config) ->
Config.
Expand All @@ -233,7 +234,8 @@ end_per_group(domain_permissions, _Config) ->
meck:unload(mongoose_domain_api);
end_per_group(use_directive, Config) ->
unmeck_domain_api(Config),
unmeck_module_and_service_checking(Config);
unmeck_module_and_service_checking(Config),
mongoose_config:erase_opts();
end_per_group(_, Config) ->
Config.

Expand Down Expand Up @@ -936,7 +938,7 @@ use_dir_object_module_and_db_not_loaded(Config) ->
#{code := deps_not_loaded,
not_loaded_modules := [<<"mod_x">>],
not_loaded_internal_databases := [<<"db_x">>]},
message :=
message :=
<<"Some of the required modules and internal databases are not loaded">>,
path := [<<"catD">>, <<"command">>]
} = Error.
Expand All @@ -950,7 +952,7 @@ use_dir_object_service_and_db_not_loaded(Config) ->
#{code := deps_not_loaded,
not_loaded_services := [<<"service_x">>],
not_loaded_internal_databases := [<<"db_x">>]},
message := <<"Some of the required services and internal databases are not loaded">>,
message := <<"Some of the required services and internal databases are not loaded">>,
path := [<<"catD">>, <<"command3">>]
} = Error.

Expand All @@ -970,39 +972,22 @@ use_dir_object_module_service_and_db_loaded(Config) ->
path := [<<"catB">>, <<"command">>]
} = Error.

use_dir_auth_user_all_modules_services_and_dbs_loaded(Config) ->
use_dir_auth_all_modules_services_and_dbs_loaded(UserRole, Config) ->
Doc = <<"{ catC { command2 } }">>,
Ctx = #{user => jid:make_bare(<<"user">>, <<"localhost">>)},
Ctx = #{user => jid:make_bare(UserRole, <<"localhost">>)},
{Ast, Ctx2} = check_directives(Config, Ctx, Doc),
Res = execute_ast(Config, Ctx2, Ast),
?assertEqual(#{data => #{<<"catC">> => #{<<"command2">> => <<"command2">>}}}, Res).

use_dir_auth_admin_all_modules_services_and_dbs_loaded(Config) ->
Doc = <<"{ catC { command2 } }">>,
Ctx = #{user => jid:make_bare(<<"admin">>, <<"localhost">>)},
{Ast, Ctx2} = check_directives(Config, Ctx, Doc),
Res = execute_ast(Config, Ctx2, Ast),
?assertEqual(#{data => #{<<"catC">> => #{<<"command2">> => <<"command2">>}}}, Res).
use_dir_auth_user_all_modules_services_and_dbs_loaded(Config) ->
use_dir_auth_all_modules_services_and_dbs_loaded(<<"user">>, Config).

use_dir_auth_user_module_service_and_db_not_loaded(Config) ->
Doc = <<"{ catB { command2 } }">>,
Ctx = #{user => jid:make_bare(<<"user">>, <<"localhost">>)},
{Ast, Ctx2} = check_directives(Config, Ctx, Doc),
#{errors := [Error]} = execute_ast(Config, Ctx2, Ast),
#{extensions :=
#{code := deps_not_loaded,
not_loaded_modules := [<<"mod_x">>],
not_loaded_services := [<<"service_x">>],
not_loaded_internal_databases := [<<"db_x">>]
},
message :=
<<"Some of the required modules and services and internal databases are not loaded">>,
path := [<<"catB">>, <<"command2">>]
} = Error.
use_dir_auth_admin_all_modules_services_and_dbs_loaded(Config) ->
use_dir_auth_all_modules_services_and_dbs_loaded(<<"admin">>, Config).

use_dir_auth_admin_module_service_and_db_not_loaded(Config) ->
use_dir_auth_module_service_and_db_not_loaded(UserRole, Config) ->
Doc = <<"{ catB { command2 } }">>,
Ctx = #{user => jid:make_bare(<<"admin">>, <<"localhost">>)},
Ctx = #{user => jid:make_bare(UserRole, <<"localhost">>)},
{Ast, Ctx2} = check_directives(Config, Ctx, Doc),
#{errors := [Error]} = execute_ast(Config, Ctx2, Ast),
#{extensions :=
Expand All @@ -1016,21 +1001,15 @@ use_dir_auth_admin_module_service_and_db_not_loaded(Config) ->
path := [<<"catB">>, <<"command2">>]
} = Error.

use_dir_auth_user_db_not_loaded(Config) ->
Doc = <<"{ catD { command2 } }">>,
Ctx = #{user => jid:make_bare(<<"user">>, <<"localhost">>)},
{Ast, Ctx2} = check_directives(Config, Ctx, Doc),
#{errors := [Error]} = execute_ast(Config, Ctx2, Ast),
#{extensions :=
#{code := deps_not_loaded,
not_loaded_internal_databases := [<<"db_x">>]},
message := <<"Some of the required internal databases are not loaded">>,
path := [<<"catD">>, <<"command2">>]
} = Error.
use_dir_auth_user_module_service_and_db_not_loaded(Config) ->
use_dir_auth_module_service_and_db_not_loaded(<<"user">>, Config).

use_dir_auth_admin_db_not_loaded(Config) ->
use_dir_auth_admin_module_service_and_db_not_loaded(Config) ->
use_dir_auth_module_service_and_db_not_loaded(<<"admin">>, Config).

use_dir_auth_db_not_loaded(UserRole, Config) ->
Doc = <<"{ catD { command2 } }">>,
Ctx = #{user => jid:make_bare(<<"admin">>, <<"localhost">>)},
Ctx = #{user => jid:make_bare(UserRole, <<"localhost">>)},
{Ast, Ctx2} = check_directives(Config, Ctx, Doc),
#{errors := [Error]} = execute_ast(Config, Ctx2, Ast),
#{extensions :=
Expand All @@ -1040,6 +1019,12 @@ use_dir_auth_admin_db_not_loaded(Config) ->
path := [<<"catD">>, <<"command2">>]
} = Error.

use_dir_auth_user_db_not_loaded(Config) ->
use_dir_auth_db_not_loaded(<<"user">>, Config).

use_dir_auth_admin_db_not_loaded(Config) ->
use_dir_auth_db_not_loaded(<<"admin">>, Config).

%% Helpers

assert_code(Code, Data) ->
Expand Down Expand Up @@ -1244,27 +1229,17 @@ meck_module_and_service_checking(Config) ->
LoadedModules = #{<<"test-domain.com">> => [mod_a, mod_d],
<<"localhost">> => [mod_a, mod_b, mod_c]},
LoadedServices = [service_a, service_b],
LoadedDBs = [db_a],
% gen_mod
meck:new(gen_mod, [no_link]),
meck:expect(gen_mod, is_loaded,
fun (Domain, M) -> lists:member(M, maps:get(Domain, LoadedModules, [])) end),
% mongoose_service
meck:new(mongoose_service, [no_link]),
meck:expect(mongoose_service, is_loaded, fun (M) -> lists:member(M, LoadedServices) end),
% mongoose_config
meck:new(mongoose_config, [no_link]),
meck:expect(mongoose_config, get_opt, fun ([internal_databases, M], undefined) ->
case lists:member(M, LoadedDBs) of
true -> M;
false -> undefined
end
end),
[{loaded_services, LoadedServices},
{loaded_modules, LoadedModules},
{loaded_dbs, LoadedDBs} | Config].
{loaded_modules, LoadedModules} | Config].

unmeck_module_and_service_checking(_Config) ->
meck:unload(gen_mod),
meck:unload(mongoose_service),
meck:unload(mongoose_config).
mongoose_config:erase_opts().

0 comments on commit 0ff0376

Please sign in to comment.