From 32f0c23810d140ede7a939065b24a6d62c82f131 Mon Sep 17 00:00:00 2001 From: jacekwegr Date: Fri, 15 Dec 2023 09:39:42 +0100 Subject: [PATCH 1/4] Add `internal_databases` to the `@use` directive --- priv/graphql/schemas/admin/cets.gql | 6 +-- priv/graphql/schemas/admin/mnesia.gql | 22 +++++----- priv/graphql/schemas/global/use_dir.gql | 2 + .../mongoose_graphql_directive_use.erl | 42 ++++++++++++++----- 4 files changed, 47 insertions(+), 25 deletions(-) diff --git a/priv/graphql/schemas/admin/cets.gql b/priv/graphql/schemas/admin/cets.gql index 8f4f3b86ac..5ab9b99870 100644 --- a/priv/graphql/schemas/admin/cets.gql +++ b/priv/graphql/schemas/admin/cets.gql @@ -1,11 +1,11 @@ "Allow admin to get information about CETS status" -type CETSAdminQuery @protected{ +type CETSAdminQuery @use(internal_databases: ["cets"]) @protected{ "Get a list of tables from the local node" tableInfo: [CETSTableInfo] - @protected(type: GLOBAL) + @protected(type: GLOBAL) @use "Get status of CETS" systemInfo: CETSSystemInfo - @protected(type: GLOBAL) + @protected(type: GLOBAL) @use } type CETSTableInfo { diff --git a/priv/graphql/schemas/admin/mnesia.gql b/priv/graphql/schemas/admin/mnesia.gql index 00ce17adc6..dd621d1270 100644 --- a/priv/graphql/schemas/admin/mnesia.gql +++ b/priv/graphql/schemas/admin/mnesia.gql @@ -1,44 +1,44 @@ """ Allow admin to acquire information about mnesia database """ -type MnesiaAdminQuery @protected{ +type MnesiaAdminQuery @use(internal_databases: ["mnesia"]) @protected{ """ Get the information about appropriate mnesia property for a specified key, if no keys are provided all the available properties will be returned """ systemInfo(keys: [String!]): [MnesiaInfo] - @protected(type: GLOBAL) + @protected(type: GLOBAL) @use } """ Allow admin to backup, dump, load, restore and modify mnesia database """ -type MnesiaAdminMutation @protected{ +type MnesiaAdminMutation @use(internal_databases: ["mnesia"]) @protected{ "Set mnesia's master node" setMaster(node: NodeName!): String - @protected(type: GLOBAL) + @protected(type: GLOBAL) @use "Change nodename from 'fromString' to 'toString' in 'source' backup file and create new 'target' backup file" changeNodename(fromString: NodeName!, toString: NodeName!, source: String!, target: String!): String - @protected(type: GLOBAL) + @protected(type: GLOBAL) @use "Save mnesia backup to file 'path'" backup(path: String!): String - @protected(type: GLOBAL) + @protected(type: GLOBAL) @use "Restore mnesia backup from file 'path'" restore(path: String!): String - @protected(type: GLOBAL) + @protected(type: GLOBAL) @use "Dump mnesia to file 'path'" dump(path: String!): String - @protected(type: GLOBAL) + @protected(type: GLOBAL) @use "Dump mnesia table 'table' to file 'path'" dumpTable(path: String!, table: String!): String - @protected(type: GLOBAL) + @protected(type: GLOBAL) @use "Load mnesia from file 'path' that was previously dumped" load(path: String!): String - @protected(type: GLOBAL) + @protected(type: GLOBAL) @use "Install mnesia fallback" installFallback(path: String!): String - @protected(type: GLOBAL) + @protected(type: GLOBAL) @use } union MnesiaInfo = MnesiaStringResponse | MnesiaListResponse | MnesiaIntResponse diff --git a/priv/graphql/schemas/global/use_dir.gql b/priv/graphql/schemas/global/use_dir.gql index ece15d131c..325be79a5c 100644 --- a/priv/graphql/schemas/global/use_dir.gql +++ b/priv/graphql/schemas/global/use_dir.gql @@ -6,5 +6,7 @@ directive @use( modules: [String!] = [], "The list of services used by the category or command" services: [String!] = [], + "The list of internal databases used by the category or command" + internal_databases: [String!] = [], "The name of argument that contains domain or host type" arg: String) on FIELD_DEFINITION | OBJECT diff --git a/src/graphql/directive/mongoose_graphql_directive_use.erl b/src/graphql/directive/mongoose_graphql_directive_use.erl index a32cfb2188..34975f6f8b 100644 --- a/src/graphql/directive/mongoose_graphql_directive_use.erl +++ b/src/graphql/directive/mongoose_graphql_directive_use.erl @@ -42,6 +42,7 @@ -type use_ctx() :: #{modules := [binary()], services := [binary()], + internal_databases := [binary()], arg => binary(), atom => term()}. @@ -49,14 +50,16 @@ %% 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} = UseCtx = aggregate_use_ctx(Args, Ctx), + #{modules := Modules, services := Services, internal_databases := DB} = + UseCtx = aggregate_use_ctx(Args, Ctx), UnloadedServices = filter_unloaded_services(Services), UnloadedModules = filter_unloaded_modules(UseCtx, Ctx, Modules), - case {UnloadedModules, UnloadedServices} of - {[], []} -> + UnloadedDBs = filter_unloaded_db(DB), + case {UnloadedModules, UnloadedServices, UnloadedDBs} of + {[], [], []} -> Field; - {_, _} -> - Fun = resolve_not_loaded_fun(UnloadedModules, UnloadedServices), + {_, _, _} -> + Fun = resolve_not_loaded_fun(UnloadedModules, UnloadedServices, UnloadedDBs), Field#schema_field{resolve = Fun} end. @@ -76,15 +79,21 @@ get_arg_value(_UseCtx, #{admin := #jid{lserver = Domain}}) -> Domain. -spec aggregate_use_ctx(list(), ctx()) -> use_ctx(). -aggregate_use_ctx(Args, #{use_dir := #{modules := Modules0, services := Services0}}) -> - #{modules := Modules, services := Services} = UseCtx = prepare_use_dir_args(Args), - UseCtx#{modules => Modules0 ++ Modules, services => Services0 ++ Services}; +aggregate_use_ctx(Args, #{use_dir := #{modules := Modules0, services := Services0, + internal_databases := DB0}}) -> + #{modules := Modules, services := Services, internal_databases := DB} = + UseCtx = prepare_use_dir_args(Args), + UpdatedModules = Modules0 ++ Modules, + UpdatedServices = Services0 ++ Services, + UpdatedDB = DB0 ++ DB, + UseCtx#{modules => UpdatedModules, services => UpdatedServices, + internal_databases => UpdatedDB}; aggregate_use_ctx(Args, _Ctx) -> prepare_use_dir_args(Args). -spec prepare_use_dir_args([{graphql:name(), term()}]) -> use_ctx(). prepare_use_dir_args(Args) -> - Default = #{modules => [], services => []}, + Default = #{modules => [], services => [], internal_databases => []}, RdyArgs = maps:from_list([{binary_to_existing_atom(name(N)), V} || {N, V} <- Args]), maps:merge(Default, RdyArgs). @@ -128,8 +137,19 @@ filter_unloaded_services(Services) -> lists:filter(fun(S) -> not mongoose_service:is_loaded(binary_to_existing_atom(S)) end, Services). --spec resolve_not_loaded_fun([binary()], [binary()]) -> resolver(). -resolve_not_loaded_fun(Modules, 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, []) -> Msg = <<"Some of required modules or services are not loaded">>, Extra = #{not_loaded_modules => Modules, not_loaded_services => Services}, + fun(_, _, _, _) -> mongoose_graphql_helper:make_error(deps_not_loaded, Msg, Extra) end; +resolve_not_loaded_fun(_Modules, _Services, Databases) -> + Msg = <<"The required internal databases is not configured">>, + Extra = #{not_loaded_databases => Databases}, fun(_, _, _, _) -> mongoose_graphql_helper:make_error(deps_not_loaded, Msg, Extra) end. From ec134278d9ec6ef386490f4ae2be0e9ce865123d Mon Sep 17 00:00:00 2001 From: jacekwegr Date: Fri, 15 Dec 2023 09:41:04 +0100 Subject: [PATCH 2/4] Tests for `internal_databases` GraphQL option --- big_tests/tests/graphql_cets_SUITE.erl | 58 ++++++++-- big_tests/tests/graphql_helper.erl | 4 + big_tests/tests/graphql_mnesia_SUITE.erl | 80 ++++++++++++-- .../mongoose_graphql_directive_use.erl | 2 +- test/mongoose_graphql_SUITE.erl | 104 +++++++++++++++--- .../directives.gql | 3 +- .../directives_schema.gql | 22 +++- test/mongoose_graphql_default_resolver.erl | 5 +- 8 files changed, 239 insertions(+), 39 deletions(-) diff --git a/big_tests/tests/graphql_cets_SUITE.erl b/big_tests/tests/graphql_cets_SUITE.erl index 54a30bba69..e19388a2c7 100644 --- a/big_tests/tests/graphql_cets_SUITE.erl +++ b/big_tests/tests/graphql_cets_SUITE.erl @@ -6,17 +6,20 @@ -import(distributed_helper, [mim/0, mim2/0, rpc/4]). -import(domain_helper, [host_type/1]). -import(mongooseimctl_helper, [rpc_call/3]). --import(graphql_helper, [execute_command/4, get_unauthorized/1, get_ok_value/2]). +-import(graphql_helper, [execute_command/4, get_unauthorized/1, get_ok_value/2, + get_db_not_configured/1]). all() -> [{group, admin_cets_cli}, {group, admin_cets_http}, - {group, domain_admin_cets}]. + {group, domain_admin_cets}, + {group, cets_not_configured}]. groups() -> [{admin_cets_http, [parallel], admin_cets_tests()}, {admin_cets_cli, [parallel], admin_cets_tests()}, - {domain_admin_cets, [], domain_admin_tests()}]. + {domain_admin_cets, [], domain_admin_tests()}, + {cets_not_configured, [parallel], cets_not_configured_test()}]. admin_cets_tests() -> [has_sm_table_in_info, @@ -37,6 +40,10 @@ domain_admin_tests() -> [domain_admin_get_table_info_test, domain_admin_get_system_info_test]. +cets_not_configured_test() -> + [get_table_info_not_configured_test, + get_system_info_not_configured_test]. + init_per_suite(Config) -> case rpc_call(mongoose_config, get_opt, [[internal_databases, cets, backend], undefined]) of rdbms -> @@ -46,24 +53,49 @@ init_per_suite(Config) -> ok = rpc_call(cets_discovery, wait_for_ready, [mongoose_cets_discovery, 5000]), Config2 ++ distributed_helper:require_rpc_nodes([mim, mim2]); _ -> - {skip, "CETS is not configured with RDBMS"} + Config end. end_per_suite(Config) -> - ensure_bad_node_unregistered(), - escalus:end_per_suite(Config). + case rpc_call(mongoose_config, get_opt, [[internal_databases, cets, backend], undefined]) of + rdbms -> + ensure_bad_node_unregistered(), + escalus:end_per_suite(Config); + _ -> + ok + end. init_per_group(admin_cets_http, Config) -> - graphql_helper:init_admin_handler(Config); + Config1 = graphql_helper:init_admin_handler(Config), + skip_if_cets_not_configured(Config1); init_per_group(admin_cets_cli, Config) -> - graphql_helper:init_admin_cli(Config); + Config1 = graphql_helper:init_admin_cli(Config), + skip_if_cets_not_configured(Config1); init_per_group(domain_admin_cets, Config) -> - graphql_helper:init_domain_admin_handler(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 -> + graphql_helper:init_admin_handler(Config); + _ -> + {skip, "CETS is configured"} + end. +end_per_group(cets_not_configured, _Config) -> + graphql_helper:clean(); end_per_group(_, _Config) -> graphql_helper:clean(), escalus_fresh:clean(). +skip_if_cets_not_configured(Config) -> + case rpc_call(mongoose_config, get_opt, [[internal_databases, cets, backend], undefined]) of + rdbms -> + Config; + _ -> + {skip, "CETS is not configured with RDBMS"} + end. + init_per_testcase(has_sm_table_in_info, Config) -> case rpc_call(ejabberd_sm, sm_backend, []) of ejabberd_sm_cets -> @@ -186,6 +218,14 @@ domain_admin_get_table_info_test(Config) -> domain_admin_get_system_info_test(Config) -> get_unauthorized(get_system_info(Config)). +% CETS not configured tests + +get_table_info_not_configured_test(Config) -> + get_db_not_configured(get_table_info(Config)). + +get_system_info_not_configured_test(Config) -> + get_db_not_configured(get_system_info(Config)). + %-------------------------------------------------------------------------------------------------- % Helpers %-------------------------------------------------------------------------------------------------- diff --git a/big_tests/tests/graphql_helper.erl b/big_tests/tests/graphql_helper.erl index 59443be8db..facba59828 100644 --- a/big_tests/tests/graphql_helper.erl +++ b/big_tests/tests/graphql_helper.erl @@ -202,6 +202,10 @@ get_not_loaded(Resp) -> ?assertEqual(<<"deps_not_loaded">>, get_err_code(Resp)), ?assertEqual(<<"Some of required modules or services are not loaded">>, get_err_msg(Resp)). +get_db_not_configured(Resp) -> + ?assertEqual(<<"deps_not_loaded">>, get_err_code(Resp)), + ?assertEqual(<<"The required internal databases are not configured">>, get_err_msg(Resp)). + get_err_code(Resp) -> get_value([extensions, code], get_error(1, Resp)). diff --git a/big_tests/tests/graphql_mnesia_SUITE.erl b/big_tests/tests/graphql_mnesia_SUITE.erl index 7c93551f8b..375f467894 100644 --- a/big_tests/tests/graphql_mnesia_SUITE.erl +++ b/big_tests/tests/graphql_mnesia_SUITE.erl @@ -8,7 +8,7 @@ -import(mongooseimctl_helper, [rpc_call/3]). -import(graphql_helper, [execute_command/4, execute_user_command/5, user_to_bin/1, get_ok_value/2, get_err_code/1, get_err_value/2, get_unauthorized/1, - get_coercion_err_msg/1]). + get_coercion_err_msg/1, get_db_not_configured/1]). -record(mnesia_table_test, {key :: integer(), name :: binary()}). -record(vcard, {us, vcard}). @@ -16,12 +16,14 @@ all() -> [{group, admin_mnesia_cli}, {group, admin_mnesia_http}, - {group, domain_admin_mnesia}]. + {group, domain_admin_mnesia}, + {group, mnesia_not_configured}]. groups() -> [{admin_mnesia_http, [sequence], admin_mnesia_tests()}, {admin_mnesia_cli, [sequence], admin_mnesia_tests()}, - {domain_admin_mnesia, [], domain_admin_tests()}]. + {domain_admin_mnesia, [], domain_admin_tests()}, + {mnesia_not_configured, [parallel], mnesia_not_configured_tests()}]. admin_mnesia_tests() -> [dump_mnesia_table_test, @@ -64,6 +66,18 @@ domain_admin_tests() -> domain_admin_set_master_test, domain_admin_get_info_test]. +mnesia_not_configured_tests() -> + [backup_not_configured_test, + change_nodename_not_configured_test, + dump_not_configured_test, + dump_table_not_configured_test, + install_fallback_not_configured_test, + load_not_configured_test, + restore_not_configured_test, + set_master_not_configured_test, + system_info_not_configured_test + ]. + init_per_suite(Config) -> application:ensure_all_started(jid), ok = mnesia:create_schema([node()]), @@ -76,16 +90,33 @@ end_per_suite(_C) -> mnesia:delete_schema([node()]). init_per_group(admin_mnesia_http, Config) -> - graphql_helper:init_admin_handler(Config); + Config1 = graphql_helper:init_admin_handler(Config), + skip_if_mnesia_not_configured(Config1); init_per_group(admin_mnesia_cli, Config) -> - graphql_helper:init_admin_cli(Config); + Config1 = graphql_helper:init_admin_cli(Config), + skip_if_mnesia_not_configured(Config1); init_per_group(domain_admin_mnesia, Config) -> - graphql_helper:init_domain_admin_handler(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 -> + graphql_helper:init_admin_handler(Config); + _ -> + {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 -> + {skip, "Mnesia is not configured"}; + _ -> + Config + end. + % Admin tests dump_mnesia_table_test(Config) -> @@ -313,6 +344,38 @@ domain_admin_set_master_test(Config) -> domain_admin_get_info_test(Config) -> get_unauthorized(get_info([<<"running_db_nodes">>], Config)). +backup_not_configured_test(Config) -> + Filename = <<"backup_not_configured_test">>, + get_db_not_configured(backup_mnesia(Filename, Config)). + +change_nodename_not_configured_test(Config) -> + Filename1 = <<"change_nodename_not_configured_test">>, + Filename2 = <<"change_nodename2_not_configured_test">>, + ChangeFrom = <<"mongooseim@localhost">>, + ChangeTo = <<"change_nodename_not_configured_test@localhost">>, + get_db_not_configured(change_nodename(ChangeFrom, ChangeTo, Filename1, Filename2, Config)). + +dump_not_configured_test(Config) -> + get_db_not_configured(dump_mnesia(<<"File">>, Config)). + +dump_table_not_configured_test(Config) -> + get_db_not_configured(dump_mnesia_table(<<"File">>, <<"mnesia_table_test">>, Config)). + +install_fallback_not_configured_test(Config) -> + get_db_not_configured(install_fallback(<<"Path">>, Config)). + +load_not_configured_test(Config) -> + get_db_not_configured(load_mnesia(<<"Path">>, Config)). + +restore_not_configured_test(Config) -> + get_db_not_configured(restore_mnesia(<<"Path">>, Config)). + +set_master_not_configured_test(Config) -> + get_db_not_configured(set_master(mim(), Config)). + +system_info_not_configured_test(Config) -> + get_db_not_configured(get_info([<<"running_db_nodes">>], Config)). + %-------------------------------------------------------------------------------------------------- % Helpers %-------------------------------------------------------------------------------------------------- @@ -361,8 +424,7 @@ create_file(FullPath) -> file:close(FullPath). create_and_write_file(FullPath) -> - {ok, File} = file:open(FullPath, [write]), - io:format(File, "~s~n", ["TEST"]), + {ok, _File} = file:open(FullPath, [write]), file:close(FullPath). check_if_response_contains(Response, String) -> diff --git a/src/graphql/directive/mongoose_graphql_directive_use.erl b/src/graphql/directive/mongoose_graphql_directive_use.erl index 34975f6f8b..c9edbf0e90 100644 --- a/src/graphql/directive/mongoose_graphql_directive_use.erl +++ b/src/graphql/directive/mongoose_graphql_directive_use.erl @@ -150,6 +150,6 @@ resolve_not_loaded_fun(Modules, Services, []) -> Extra = #{not_loaded_modules => Modules, not_loaded_services => Services}, fun(_, _, _, _) -> mongoose_graphql_helper:make_error(deps_not_loaded, Msg, Extra) end; resolve_not_loaded_fun(_Modules, _Services, Databases) -> - Msg = <<"The required internal databases is not configured">>, + Msg = <<"The required internal databases are not configured">>, Extra = #{not_loaded_databases => Databases}, fun(_, _, _, _) -> mongoose_graphql_helper:make_error(deps_not_loaded, Msg, Extra) end. diff --git a/test/mongoose_graphql_SUITE.erl b/test/mongoose_graphql_SUITE.erl index 8e8ce1a296..dc3f7fff0f 100644 --- a/test/mongoose_graphql_SUITE.erl +++ b/test/mongoose_graphql_SUITE.erl @@ -113,12 +113,17 @@ use_directive() -> use_dir_all_modules_loaded, use_dir_all_modules_and_services_loaded, use_dir_module_and_service_not_loaded, + use_dir_db_loaded, + use_dir_db_not_loaded, use_dir_object_module_and_service_not_loaded, - use_dir_object_all_modules_and_services_loaded, - use_dir_auth_admin_all_modules_and_services_loaded, - use_dir_auth_user_all_modules_and_services_loaded, + use_dir_object_all_modules_services_and_db_loaded, + use_dir_object_db_not_loaded, + use_dir_auth_admin_all_modules_services_and_db_loaded, + use_dir_auth_user_all_modules_services_and_db_loaded, use_dir_auth_admin_module_and_service_not_loaded, - use_dir_auth_user_module_and_service_not_loaded + use_dir_auth_user_module_and_service_not_loaded, + use_dir_auth_admin_db_not_loaded, + use_dir_auth_user_db_not_loaded ]. user_listener() -> @@ -154,7 +159,7 @@ common_tests() -> init_per_suite(Config) -> %% Register atoms for `binary_to_existing_atom` - [mod_x, mod_z, service_x, service_d], + [mod_x, mod_z, service_x, service_d, db_x], application:ensure_all_started(cowboy), application:ensure_all_started(jid), Config. @@ -276,13 +281,18 @@ init_per_testcase(C, Config) when C =:= check_object_permissions; init_per_testcase(C, Config) when C =:= use_dir_module_not_loaded; C =:= use_dir_all_modules_loaded; C =:= use_dir_module_and_service_not_loaded; + C =:= use_dir_db_loaded; + C =:= use_dir_db_not_loaded; C =:= use_dir_all_modules_and_services_loaded; C =:= use_dir_object_module_and_service_not_loaded; - C =:= use_dir_object_all_modules_and_services_loaded; - C =:= use_dir_auth_user_all_modules_and_services_loaded; - C =:= use_dir_auth_admin_all_modules_and_services_loaded; + C =:= use_dir_object_all_modules_services_and_db_loaded; + C =:= use_dir_object_db_not_loaded; + C =:= use_dir_auth_user_all_modules_services_and_db_loaded; + C =:= use_dir_auth_admin_all_modules_services_and_db_loaded; C =:= use_dir_auth_user_module_and_service_not_loaded; - C =:= use_dir_auth_admin_module_and_service_not_loaded -> + C =:= use_dir_auth_admin_module_and_service_not_loaded; + C =:= use_dir_auth_admin_db_not_loaded; + C =:= use_dir_auth_user_db_not_loaded -> {Mapping, Pattern} = example_directives_schema_data(Config), {ok, _} = mongoose_graphql:create_endpoint(C, Mapping, [Pattern]), Ep = mongoose_graphql:get_endpoint(C), @@ -874,13 +884,44 @@ use_dir_module_and_service_not_loaded(Config) -> path := [<<"catA">>, <<"command3">>] } = Error. -use_dir_object_all_modules_and_services_loaded(Config) -> +use_dir_db_loaded(Config) -> + Doc = <<"{catA { command4(domain: \"localhost\")} }">>, + Ctx = #{}, + {Ast, Ctx2} = check_directives(Config, Ctx, Doc), + Res = execute_ast(Config, Ctx2, Ast), + ?assertEqual(#{data => #{<<"catA">> => #{<<"command4">> => <<"command4">>}}}, Res). + +use_dir_db_not_loaded(Config) -> + Doc = <<"{catA { command5(domain: \"localhost\")} }">>, + Ctx = #{}, + {Ast, Ctx2} = check_directives(Config, Ctx, Doc), + #{errors := [Error]} = execute_ast(Config, Ctx2, Ast), + #{extensions := + #{code := deps_not_loaded, + not_loaded_databases := [<<"db_x">>]}, + message := <<"The required internal databases are not configured">>, + path := [<<"catA">>, <<"command5">>] + } = Error. + +use_dir_object_all_modules_services_and_db_loaded(Config) -> Doc = <<"{ catC { command(domain: \"localhost\") } }">>, Ctx = #{}, {Ast, Ctx2} = check_directives(Config, Ctx, Doc), Res = execute_ast(Config, Ctx2, Ast), ?assertEqual(#{data => #{<<"catC">> => #{<<"command">> => <<"command">>}}}, Res). +use_dir_object_db_not_loaded(Config) -> + Doc = <<"{ catD { command(domain: \"localhost\") } }">>, + Ctx = #{}, + {Ast, Ctx2} = check_directives(Config, Ctx, Doc), + #{errors := [Error]} = execute_ast(Config, Ctx2, Ast), + #{extensions := + #{code := deps_not_loaded, + not_loaded_databases := [<<"db_x">>]}, + message := <<"The required internal databases are not configured">>, + path := [<<"catD">>, <<"command">>] + } = Error. + use_dir_object_module_and_service_not_loaded(Config) -> Doc = <<"{ catB { command(domain: \"localhost\") } }">>, Ctx = #{}, @@ -895,14 +936,14 @@ use_dir_object_module_and_service_not_loaded(Config) -> path := [<<"catB">>, <<"command">>] } = Error. -use_dir_auth_user_all_modules_and_services_loaded(Config) -> +use_dir_auth_user_all_modules_services_and_db_loaded(Config) -> Doc = <<"{ catC { command2 } }">>, Ctx = #{user => jid:make_bare(<<"user">>, <<"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_and_services_loaded(Config) -> +use_dir_auth_admin_all_modules_services_and_db_loaded(Config) -> Doc = <<"{ catC { command2 } }">>, Ctx = #{user => jid:make_bare(<<"admin">>, <<"localhost">>)}, {Ast, Ctx2} = check_directives(Config, Ctx, Doc), @@ -937,6 +978,30 @@ use_dir_auth_admin_module_and_service_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_databases := [<<"db_x">>]}, + message := <<"The required internal databases are not configured">>, + path := [<<"catD">>, <<"command2">>] + } = Error. + +use_dir_auth_admin_db_not_loaded(Config) -> + Doc = <<"{ catD { command2 } }">>, + Ctx = #{user => jid:make_bare(<<"admin">>, <<"localhost">>)}, + {Ast, Ctx2} = check_directives(Config, Ctx, Doc), + #{errors := [Error]} = execute_ast(Config, Ctx2, Ast), + #{extensions := + #{code := deps_not_loaded, + not_loaded_databases := [<<"db_x">>]}, + message := <<"The required internal databases are not configured">>, + path := [<<"catD">>, <<"command2">>] + } = Error. + %% Helpers assert_code(Code, Data) -> @@ -1141,6 +1206,7 @@ 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, @@ -1148,9 +1214,19 @@ meck_module_and_service_checking(Config) -> % 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} | Config]. + {loaded_modules, LoadedModules}, + {loaded_dbs, LoadedDBs} | Config]. unmeck_module_and_service_checking(_Config) -> meck:unload(gen_mod), - meck:unload(mongoose_service). + meck:unload(mongoose_service), + meck:unload(mongoose_config). diff --git a/test/mongoose_graphql_SUITE_data/directives.gql b/test/mongoose_graphql_SUITE_data/directives.gql index c969d3d011..1dc2bbd72a 100644 --- a/test/mongoose_graphql_SUITE_data/directives.gql +++ b/test/mongoose_graphql_SUITE_data/directives.gql @@ -12,7 +12,8 @@ enum ProtectionType{ DEFAULT } -directive @use (modules: [String!] = [], services: [String!] = []) on FIELD_DEFINITION | OBJECT +directive @use (modules: [String!] = [], services: [String!] = [], + internal_databases: [String!] = []) on FIELD_DEFINITION | OBJECT type UserQuery @use{ field: String diff --git a/test/mongoose_graphql_SUITE_data/directives_schema.gql b/test/mongoose_graphql_SUITE_data/directives_schema.gql index f0b2ed1d4d..2df9c38f35 100644 --- a/test/mongoose_graphql_SUITE_data/directives_schema.gql +++ b/test/mongoose_graphql_SUITE_data/directives_schema.gql @@ -12,12 +12,14 @@ enum ProtectionType{ DEFAULT } -directive @use(modules: [String!] = [], services: [String!] = [], arg: String) on FIELD_DEFINITION | OBJECT +directive @use(modules: [String!] = [], services: [String!] = [], + internal_databases: [String!] = [], arg: String) on FIELD_DEFINITION | OBJECT type UserQuery { catA: Category catB: CategoryB catC: CategoryC + catD: CategoryD } type Category @protected { @@ -27,10 +29,14 @@ type Category @protected { @use(modules: ["mod_b"], services: ["service_a", "service_b"], arg: "domain") command3(domain: String): String @use(modules: ["mod_a", "mod_z"], services: ["service_a", "service_d"], arg: "domain") + command4(domain: String): String + @use(modules: ["mod_a"], services: ["service_a"], internal_databases: ["db_a"], arg: "domain") + command5(domain: String): String + @use(modules: ["mod_a"], services: ["service_a"], internal_databases: ["db_x"], arg: "domain") } type CategoryB - @use(modules: ["mod_x"], services: ["service_x"]) + @use(modules: ["mod_x"], services: ["service_x"], internal_databases: ["db_a"]) @protected { command(domain: String): String @use(modules: ["mod_a"], arg: "domain") @@ -39,7 +45,7 @@ type CategoryB } type CategoryC - @use(modules: ["mod_a"], services: ["service_a"]) + @use(modules: ["mod_a"], services: ["service_a"], internal_databases: ["db_a"]) @protected { command(domain: String): String @use(modules: ["mod_b"], arg: "domain") @@ -47,7 +53,15 @@ type CategoryC @use(modules: ["mod_b"]) } +type CategoryD + @use(modules: ["mod_a"], services: ["service_a"], internal_databases: ["db_x"]) + @protected { + command(domain: String): String + @use(modules: ["mod_b"], arg: "domain") + command2: String + @use +} + type UserMutation @protected{ field: String } - diff --git a/test/mongoose_graphql_default_resolver.erl b/test/mongoose_graphql_default_resolver.erl index 8c58753491..522949de87 100644 --- a/test/mongoose_graphql_default_resolver.erl +++ b/test/mongoose_graphql_default_resolver.erl @@ -13,9 +13,12 @@ execute(_Ctx, _Obj, <<"id">>, #{<<"value">> := Value}) -> execute(_Ctx, _Obj, Cmd, _Attrs) when Cmd =:= <<"catA">>; Cmd =:= <<"catB">>; Cmd =:= <<"catC">>; + Cmd =:= <<"catD">>; Cmd =:= <<"command">>; Cmd =:= <<"command2">>; - Cmd =:= <<"command3">> -> + Cmd =:= <<"command3">>; + Cmd =:= <<"command4">>; + Cmd =:= <<"command5">> -> {ok, Cmd}; execute(_Ctx, _Obj, Field, _Attrs) -> {error, {not_implemented, Field}}. From 6b45de0fa75a92d65db9464e008c2bbdac613fc3 Mon Sep 17 00:00:00 2001 From: jacekwegr Date: Fri, 15 Dec 2023 15:52:18 +0100 Subject: [PATCH 3/4] Change the message for the `@use` directive --- big_tests/tests/graphql_cets_SUITE.erl | 7 +- big_tests/tests/graphql_helper.erl | 6 +- big_tests/tests/graphql_http_upload_SUITE.erl | 4 +- big_tests/tests/graphql_mnesia_SUITE.erl | 23 +-- .../mongoose_graphql_directive_use.erl | 25 +++- test/mongoose_graphql_SUITE.erl | 132 +++++++++++------- .../directives_schema.gql | 8 +- test/mongoose_graphql_default_resolver.erl | 3 +- 8 files changed, 129 insertions(+), 79 deletions(-) diff --git a/big_tests/tests/graphql_cets_SUITE.erl b/big_tests/tests/graphql_cets_SUITE.erl index e19388a2c7..ec271005e6 100644 --- a/big_tests/tests/graphql_cets_SUITE.erl +++ b/big_tests/tests/graphql_cets_SUITE.erl @@ -6,8 +6,7 @@ -import(distributed_helper, [mim/0, mim2/0, rpc/4]). -import(domain_helper, [host_type/1]). -import(mongooseimctl_helper, [rpc_call/3]). --import(graphql_helper, [execute_command/4, get_unauthorized/1, get_ok_value/2, - get_db_not_configured/1]). +-import(graphql_helper, [execute_command/4, get_unauthorized/1, get_ok_value/2, get_not_loaded/1]). all() -> [{group, admin_cets_cli}, @@ -221,10 +220,10 @@ domain_admin_get_system_info_test(Config) -> % CETS not configured tests get_table_info_not_configured_test(Config) -> - get_db_not_configured(get_table_info(Config)). + get_not_loaded(get_table_info(Config)). get_system_info_not_configured_test(Config) -> - get_db_not_configured(get_system_info(Config)). + get_not_loaded(get_system_info(Config)). %-------------------------------------------------------------------------------------------------- % Helpers diff --git a/big_tests/tests/graphql_helper.erl b/big_tests/tests/graphql_helper.erl index facba59828..4eb23c54dd 100644 --- a/big_tests/tests/graphql_helper.erl +++ b/big_tests/tests/graphql_helper.erl @@ -200,11 +200,7 @@ get_listener_opts(EpName) -> get_not_loaded(Resp) -> ?assertEqual(<<"deps_not_loaded">>, get_err_code(Resp)), - ?assertEqual(<<"Some of required modules or services are not loaded">>, get_err_msg(Resp)). - -get_db_not_configured(Resp) -> - ?assertEqual(<<"deps_not_loaded">>, get_err_code(Resp)), - ?assertEqual(<<"The required internal databases are not configured">>, get_err_msg(Resp)). + ?assertNotEqual(nomatch, binary:match(get_err_msg(Resp), <<"Some of the required">>)). get_err_code(Resp) -> get_value([extensions, code], get_error(1, Resp)). diff --git a/big_tests/tests/graphql_http_upload_SUITE.erl b/big_tests/tests/graphql_http_upload_SUITE.erl index 2310e53a55..5bb9f4b653 100644 --- a/big_tests/tests/graphql_http_upload_SUITE.erl +++ b/big_tests/tests/graphql_http_upload_SUITE.erl @@ -213,7 +213,7 @@ user_http_upload_not_configured(Config) -> user_http_upload_not_configured(Config, Alice) -> Result = user_get_url(<<"test">>, 123, <<"Test">>, 123, Alice, Config), ?assertEqual(<<"deps_not_loaded">>, get_err_code(Result)), - ?assertEqual(<<"Some of required modules or services are not loaded">>, get_err_msg(Result)). + ?assertEqual(<<"Some of the required modules are not loaded">>, get_err_msg(Result)). % Admin test cases @@ -268,7 +268,7 @@ admin_http_upload_not_configured(Config) -> admin_http_upload_not_configured(Config, Domain) -> Result = admin_get_url(Domain, <<"test">>, 123, <<"Test">>, 123, Config), ?assertEqual(<<"deps_not_loaded">>, get_err_code(Result)), - ?assertEqual(<<"Some of required modules or services are not loaded">>, get_err_msg(Result)). + ?assertEqual(<<"Some of the required modules are not loaded">>, get_err_msg(Result)). domain_admin_get_url_no_permission(Config) -> Result1 = admin_get_url(<<"AAAAA">>, <<"test">>, 123, <<"Test">>, 123, Config), diff --git a/big_tests/tests/graphql_mnesia_SUITE.erl b/big_tests/tests/graphql_mnesia_SUITE.erl index 375f467894..7495309065 100644 --- a/big_tests/tests/graphql_mnesia_SUITE.erl +++ b/big_tests/tests/graphql_mnesia_SUITE.erl @@ -8,7 +8,7 @@ -import(mongooseimctl_helper, [rpc_call/3]). -import(graphql_helper, [execute_command/4, execute_user_command/5, user_to_bin/1, get_ok_value/2, get_err_code/1, get_err_value/2, get_unauthorized/1, - get_coercion_err_msg/1, get_db_not_configured/1]). + get_coercion_err_msg/1, get_not_loaded/1]). -record(mnesia_table_test, {key :: integer(), name :: binary()}). -record(vcard, {us, vcard}). @@ -346,35 +346,35 @@ domain_admin_get_info_test(Config) -> backup_not_configured_test(Config) -> Filename = <<"backup_not_configured_test">>, - get_db_not_configured(backup_mnesia(Filename, Config)). + get_not_loaded(backup_mnesia(Filename, Config)). change_nodename_not_configured_test(Config) -> Filename1 = <<"change_nodename_not_configured_test">>, Filename2 = <<"change_nodename2_not_configured_test">>, ChangeFrom = <<"mongooseim@localhost">>, ChangeTo = <<"change_nodename_not_configured_test@localhost">>, - get_db_not_configured(change_nodename(ChangeFrom, ChangeTo, Filename1, Filename2, Config)). + get_not_loaded(change_nodename(ChangeFrom, ChangeTo, Filename1, Filename2, Config)). dump_not_configured_test(Config) -> - get_db_not_configured(dump_mnesia(<<"File">>, Config)). + get_not_loaded(dump_mnesia(<<"File">>, Config)). dump_table_not_configured_test(Config) -> - get_db_not_configured(dump_mnesia_table(<<"File">>, <<"mnesia_table_test">>, Config)). + get_not_loaded(dump_mnesia_table(<<"File">>, <<"mnesia_table_test">>, Config)). install_fallback_not_configured_test(Config) -> - get_db_not_configured(install_fallback(<<"Path">>, Config)). + get_not_loaded(install_fallback(<<"Path">>, Config)). load_not_configured_test(Config) -> - get_db_not_configured(load_mnesia(<<"Path">>, Config)). + get_not_loaded(load_mnesia(<<"Path">>, Config)). restore_not_configured_test(Config) -> - get_db_not_configured(restore_mnesia(<<"Path">>, Config)). + get_not_loaded(restore_mnesia(<<"Path">>, Config)). set_master_not_configured_test(Config) -> - get_db_not_configured(set_master(mim(), Config)). + get_not_loaded(set_master(mim(), Config)). system_info_not_configured_test(Config) -> - get_db_not_configured(get_info([<<"running_db_nodes">>], Config)). + get_not_loaded(get_info([<<"running_db_nodes">>], Config)). %-------------------------------------------------------------------------------------------------- % Helpers @@ -424,7 +424,8 @@ create_file(FullPath) -> file:close(FullPath). create_and_write_file(FullPath) -> - {ok, _File} = file:open(FullPath, [write]), + {ok, File} = file:open(FullPath, [write]), + io:format(File, "~s~n", ["TEST"]), file:close(FullPath). check_if_response_contains(Response, String) -> diff --git a/src/graphql/directive/mongoose_graphql_directive_use.erl b/src/graphql/directive/mongoose_graphql_directive_use.erl index c9edbf0e90..a2d39f9045 100644 --- a/src/graphql/directive/mongoose_graphql_directive_use.erl +++ b/src/graphql/directive/mongoose_graphql_directive_use.erl @@ -145,11 +145,22 @@ filter_unloaded_db(DBs) -> end, DBs). -spec resolve_not_loaded_fun([binary()], [binary()], [binary()]) -> resolver(). -resolve_not_loaded_fun(Modules, Services, []) -> - Msg = <<"Some of required modules or services are not loaded">>, - Extra = #{not_loaded_modules => Modules, not_loaded_services => Services}, - fun(_, _, _, _) -> mongoose_graphql_helper:make_error(deps_not_loaded, Msg, Extra) end; -resolve_not_loaded_fun(_Modules, _Services, Databases) -> - Msg = <<"The required internal databases are not configured">>, - Extra = #{not_loaded_databases => Databases}, +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"}] + ), + MsgPrefix = <<"Some of the required ">>, + MsgList = string:join(NotLoadedDescs, " and "), + MsgBinaryList = list_to_binary(MsgList), + Msg = <>, + 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. diff --git a/test/mongoose_graphql_SUITE.erl b/test/mongoose_graphql_SUITE.erl index dc3f7fff0f..d00cb03f3e 100644 --- a/test/mongoose_graphql_SUITE.erl +++ b/test/mongoose_graphql_SUITE.erl @@ -113,15 +113,17 @@ use_directive() -> use_dir_all_modules_loaded, use_dir_all_modules_and_services_loaded, use_dir_module_and_service_not_loaded, - use_dir_db_loaded, + use_dir_module_service_and_db_loaded, use_dir_db_not_loaded, - use_dir_object_module_and_service_not_loaded, - use_dir_object_all_modules_services_and_db_loaded, - use_dir_object_db_not_loaded, - use_dir_auth_admin_all_modules_services_and_db_loaded, - use_dir_auth_user_all_modules_services_and_db_loaded, - use_dir_auth_admin_module_and_service_not_loaded, - use_dir_auth_user_module_and_service_not_loaded, + use_dir_module_service_and_db_not_loaded, + use_dir_object_module_service_and_db_loaded, + use_dir_object_all_modules_services_and_dbs_loaded, + use_dir_object_module_and_db_not_loaded, + use_dir_object_service_and_db_not_loaded, + use_dir_auth_admin_all_modules_services_and_dbs_loaded, + use_dir_auth_user_all_modules_services_and_dbs_loaded, + use_dir_auth_admin_module_service_and_db_not_loaded, + use_dir_auth_user_module_service_and_db_not_loaded, use_dir_auth_admin_db_not_loaded, use_dir_auth_user_db_not_loaded ]. @@ -281,16 +283,18 @@ init_per_testcase(C, Config) when C =:= check_object_permissions; init_per_testcase(C, Config) when C =:= use_dir_module_not_loaded; C =:= use_dir_all_modules_loaded; C =:= use_dir_module_and_service_not_loaded; - C =:= use_dir_db_loaded; + C =:= use_dir_module_service_and_db_loaded; C =:= use_dir_db_not_loaded; + C =:= use_dir_module_service_and_db_not_loaded; C =:= use_dir_all_modules_and_services_loaded; - C =:= use_dir_object_module_and_service_not_loaded; - C =:= use_dir_object_all_modules_services_and_db_loaded; - C =:= use_dir_object_db_not_loaded; - C =:= use_dir_auth_user_all_modules_services_and_db_loaded; - C =:= use_dir_auth_admin_all_modules_services_and_db_loaded; - C =:= use_dir_auth_user_module_and_service_not_loaded; - C =:= use_dir_auth_admin_module_and_service_not_loaded; + C =:= use_dir_object_module_service_and_db_loaded; + C =:= use_dir_object_all_modules_services_and_dbs_loaded; + C =:= use_dir_object_module_and_db_not_loaded; + C =:= use_dir_object_service_and_db_not_loaded; + C =:= use_dir_auth_user_all_modules_services_and_dbs_loaded; + C =:= use_dir_auth_admin_all_modules_services_and_dbs_loaded; + C =:= use_dir_auth_user_module_service_and_db_not_loaded; + C =:= use_dir_auth_admin_module_service_and_db_not_loaded; C =:= use_dir_auth_admin_db_not_loaded; C =:= use_dir_auth_user_db_not_loaded -> {Mapping, Pattern} = example_directives_schema_data(Config), @@ -691,8 +695,7 @@ use_directive_can_use_auth_user_domain(Config) -> execute(Ep, Body, {<<"alice@localhost">>, <<"makota">>}), #{<<"extensions">> := #{<<"code">> := <<"deps_not_loaded">>, - <<"not_loaded_modules">> := [<<"mod_x">>], - <<"not_loaded_services">> := []} + <<"not_loaded_modules">> := [<<"mod_x">>]} } = Error. no_creds_defined_admin_can_access_protected(_Config) -> @@ -722,8 +725,7 @@ use_directive_can_use_auth_domain_admin_domain(Config) -> execute(Ep, Body, {<<"admin@localhost">>, <<"makota">>}), #{<<"extensions">> := #{<<"code">> := <<"deps_not_loaded">>, - <<"not_loaded_modules">> := [<<"mod_x">>], - <<"not_loaded_services">> := []} + <<"not_loaded_modules">> := [<<"mod_x">>]} } = Error. auth_domain_admin_wrong_password_error(Config) -> @@ -856,10 +858,9 @@ use_dir_module_not_loaded(Config) -> #{errors := [Error]} = execute_ast(Config, Ctx2, Ast), #{extensions := #{code := deps_not_loaded, - not_loaded_modules := [<<"mod_b">>], - not_loaded_services := [] + not_loaded_modules := [<<"mod_b">>] }, - message := <<"Some of required modules or services are not loaded">>, + message := <<"Some of the required modules are not loaded">>, path := [<<"catA">>, <<"command">>] } = Error. @@ -880,11 +881,11 @@ use_dir_module_and_service_not_loaded(Config) -> not_loaded_modules := [<<"mod_z">>], not_loaded_services := [<<"service_d">>] }, - message := <<"Some of required modules or services are not loaded">>, + message := <<"Some of the required modules and services are not loaded">>, path := [<<"catA">>, <<"command3">>] } = Error. -use_dir_db_loaded(Config) -> +use_dir_module_service_and_db_loaded(Config) -> Doc = <<"{catA { command4(domain: \"localhost\")} }">>, Ctx = #{}, {Ast, Ctx2} = check_directives(Config, Ctx, Doc), @@ -898,31 +899,62 @@ use_dir_db_not_loaded(Config) -> #{errors := [Error]} = execute_ast(Config, Ctx2, Ast), #{extensions := #{code := deps_not_loaded, - not_loaded_databases := [<<"db_x">>]}, - message := <<"The required internal databases are not configured">>, + not_loaded_internal_databases := [<<"db_x">>]}, + message := + <<"Some of the required internal databases are not loaded">>, path := [<<"catA">>, <<"command5">>] } = Error. -use_dir_object_all_modules_services_and_db_loaded(Config) -> +use_dir_module_service_and_db_not_loaded(Config) -> + Doc = <<"{catA { command6(domain: \"localhost\")} }">>, + Ctx = #{}, + {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 := [<<"catA">>, <<"command6">>] + } = Error. + +use_dir_object_all_modules_services_and_dbs_loaded(Config) -> Doc = <<"{ catC { command(domain: \"localhost\") } }">>, Ctx = #{}, {Ast, Ctx2} = check_directives(Config, Ctx, Doc), Res = execute_ast(Config, Ctx2, Ast), ?assertEqual(#{data => #{<<"catC">> => #{<<"command">> => <<"command">>}}}, Res). -use_dir_object_db_not_loaded(Config) -> +use_dir_object_module_and_db_not_loaded(Config) -> Doc = <<"{ catD { command(domain: \"localhost\") } }">>, Ctx = #{}, {Ast, Ctx2} = check_directives(Config, Ctx, Doc), #{errors := [Error]} = execute_ast(Config, Ctx2, Ast), #{extensions := #{code := deps_not_loaded, - not_loaded_databases := [<<"db_x">>]}, - message := <<"The required internal databases are not configured">>, + not_loaded_modules := [<<"mod_x">>], + not_loaded_internal_databases := [<<"db_x">>]}, + message := + <<"Some of the required modules and internal databases are not loaded">>, path := [<<"catD">>, <<"command">>] } = Error. -use_dir_object_module_and_service_not_loaded(Config) -> +use_dir_object_service_and_db_not_loaded(Config) -> + Doc = <<"{ catD { command3 } }">>, + 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_services := [<<"service_x">>], + not_loaded_internal_databases := [<<"db_x">>]}, + message := <<"Some of the required services and internal databases are not loaded">>, + path := [<<"catD">>, <<"command3">>] + } = Error. + +use_dir_object_module_service_and_db_loaded(Config) -> Doc = <<"{ catB { command(domain: \"localhost\") } }">>, Ctx = #{}, {Ast, Ctx2} = check_directives(Config, Ctx, Doc), @@ -930,41 +962,45 @@ use_dir_object_module_and_service_not_loaded(Config) -> #{extensions := #{code := deps_not_loaded, not_loaded_modules := [<<"mod_x">>], - not_loaded_services := [<<"service_x">>] + not_loaded_services := [<<"service_x">>], + not_loaded_internal_databases := [<<"db_x">>] }, - message := <<"Some of required modules or services are not loaded">>, + message := + <<"Some of the required modules and services and internal databases are not loaded">>, path := [<<"catB">>, <<"command">>] } = Error. -use_dir_auth_user_all_modules_services_and_db_loaded(Config) -> +use_dir_auth_user_all_modules_services_and_dbs_loaded(Config) -> Doc = <<"{ catC { command2 } }">>, Ctx = #{user => jid:make_bare(<<"user">>, <<"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_db_loaded(Config) -> +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_module_and_service_not_loaded(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_modules := [<<"mod_x">>], + not_loaded_services := [<<"service_x">>], + not_loaded_internal_databases := [<<"db_x">>] }, - message := <<"Some of required modules or services are not loaded">>, + message := + <<"Some of the required modules and services and internal databases are not loaded">>, path := [<<"catB">>, <<"command2">>] } = Error. -use_dir_auth_admin_module_and_service_not_loaded(Config) -> +use_dir_auth_admin_module_service_and_db_not_loaded(Config) -> Doc = <<"{ catB { command2 } }">>, Ctx = #{user => jid:make_bare(<<"admin">>, <<"localhost">>)}, {Ast, Ctx2} = check_directives(Config, Ctx, Doc), @@ -972,9 +1008,11 @@ use_dir_auth_admin_module_and_service_not_loaded(Config) -> #{extensions := #{code := deps_not_loaded, not_loaded_modules := [<<"mod_x">>], - not_loaded_services := [<<"service_x">>] + not_loaded_services := [<<"service_x">>], + not_loaded_internal_databases := [<<"db_x">>] }, - message := <<"Some of required modules or services are not loaded">>, + message := + <<"Some of the required modules and services and internal databases are not loaded">>, path := [<<"catB">>, <<"command2">>] } = Error. @@ -985,8 +1023,8 @@ use_dir_auth_user_db_not_loaded(Config) -> #{errors := [Error]} = execute_ast(Config, Ctx2, Ast), #{extensions := #{code := deps_not_loaded, - not_loaded_databases := [<<"db_x">>]}, - message := <<"The required internal databases are not configured">>, + not_loaded_internal_databases := [<<"db_x">>]}, + message := <<"Some of the required internal databases are not loaded">>, path := [<<"catD">>, <<"command2">>] } = Error. @@ -997,8 +1035,8 @@ use_dir_auth_admin_db_not_loaded(Config) -> #{errors := [Error]} = execute_ast(Config, Ctx2, Ast), #{extensions := #{code := deps_not_loaded, - not_loaded_databases := [<<"db_x">>]}, - message := <<"The required internal databases are not configured">>, + not_loaded_internal_databases := [<<"db_x">>]}, + message := <<"Some of the required internal databases are not loaded">>, path := [<<"catD">>, <<"command2">>] } = Error. diff --git a/test/mongoose_graphql_SUITE_data/directives_schema.gql b/test/mongoose_graphql_SUITE_data/directives_schema.gql index 2df9c38f35..a537268351 100644 --- a/test/mongoose_graphql_SUITE_data/directives_schema.gql +++ b/test/mongoose_graphql_SUITE_data/directives_schema.gql @@ -33,10 +33,12 @@ type Category @protected { @use(modules: ["mod_a"], services: ["service_a"], internal_databases: ["db_a"], arg: "domain") command5(domain: String): String @use(modules: ["mod_a"], services: ["service_a"], internal_databases: ["db_x"], arg: "domain") + command6(domain: String): String + @use(modules: ["mod_x"], services: ["service_x"], internal_databases: ["db_x"], arg: "domain") } type CategoryB - @use(modules: ["mod_x"], services: ["service_x"], internal_databases: ["db_a"]) + @use(modules: ["mod_x"], services: ["service_x"], internal_databases: ["db_x"]) @protected { command(domain: String): String @use(modules: ["mod_a"], arg: "domain") @@ -57,9 +59,11 @@ type CategoryD @use(modules: ["mod_a"], services: ["service_a"], internal_databases: ["db_x"]) @protected { command(domain: String): String - @use(modules: ["mod_b"], arg: "domain") + @use(modules: ["mod_x"], arg: "domain") command2: String @use + command3: String + @use(services: ["service_x"]) } type UserMutation @protected{ diff --git a/test/mongoose_graphql_default_resolver.erl b/test/mongoose_graphql_default_resolver.erl index 522949de87..bce0e7b6cc 100644 --- a/test/mongoose_graphql_default_resolver.erl +++ b/test/mongoose_graphql_default_resolver.erl @@ -18,7 +18,8 @@ execute(_Ctx, _Obj, Cmd, _Attrs) when Cmd =:= <<"catA">>; Cmd =:= <<"command2">>; Cmd =:= <<"command3">>; Cmd =:= <<"command4">>; - Cmd =:= <<"command5">> -> + Cmd =:= <<"command5">>; + Cmd =:= <<"command6">> -> {ok, Cmd}; execute(_Ctx, _Obj, Field, _Attrs) -> {error, {not_implemented, Field}}. From 0ff0376dc452adcedb51e5429f0731bb3b05ff8c Mon Sep 17 00:00:00 2001 From: jacekwegr Date: Thu, 21 Dec 2023 16:10:02 +0100 Subject: [PATCH 4/4] Refactor code related to the `@use` directive --- big_tests/tests/graphql_cets_SUITE.erl | 14 ++-- big_tests/tests/graphql_mnesia_SUITE.erl | 12 +-- .../mongoose_graphql_directive_use.erl | 72 +++++++++-------- test/mongoose_graphql_SUITE.erl | 81 +++++++------------ 4 files changed, 79 insertions(+), 100 deletions(-) diff --git a/big_tests/tests/graphql_cets_SUITE.erl b/big_tests/tests/graphql_cets_SUITE.erl index ec271005e6..6d1475df00 100644 --- a/big_tests/tests/graphql_cets_SUITE.erl +++ b/big_tests/tests/graphql_cets_SUITE.erl @@ -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); _ -> @@ -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. @@ -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"} diff --git a/big_tests/tests/graphql_mnesia_SUITE.erl b/big_tests/tests/graphql_mnesia_SUITE.erl index 7495309065..ef3d34060a 100644 --- a/big_tests/tests/graphql_mnesia_SUITE.erl +++ b/big_tests/tests/graphql_mnesia_SUITE.erl @@ -99,10 +99,10 @@ 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) -> @@ -110,10 +110,10 @@ end_per_group(_, _Config) -> 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. diff --git a/src/graphql/directive/mongoose_graphql_directive_use.erl b/src/graphql/directive/mongoose_graphql_directive_use.erl index a2d39f9045..7bbe1f972c 100644 --- a/src/graphql/directive/mongoose_graphql_directive_use.erl +++ b/src/graphql/directive/mongoose_graphql_directive_use.erl @@ -45,6 +45,8 @@ 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 @@ -52,14 +54,14 @@ handle_directive(#directive{id = <<"use">>, args = Args}, #schema_field{} = Field, Ctx) -> #{modules := Modules, services := Services, internal_databases := DB} = 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)}, + {services, filter_unloaded_services(Services)}, + {internal_databases, filter_unloaded_db(DB)}], + case lists:filter(fun({_, Names}) -> Names =/= [] end, Items) of + [] -> Field; - {_, _, _} -> - Fun = resolve_not_loaded_fun(UnloadedModules, UnloadedServices, UnloadedDBs), + NotLoaded -> + Fun = resolve_not_loaded_fun(NotLoaded), Field#schema_field{resolve = Fun} end. @@ -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} = UseCtx = prepare_use_dir_args(Args), UpdatedModules = Modules0 ++ Modules, UpdatedServices = Services0 ++ Services, - UpdatedDB = DB0 ++ DB, + UpdatedDatabases = Databases0 ++ Databases, UseCtx#{modules => UpdatedModules, services => UpdatedServices, - internal_databases => UpdatedDB}; + internal_databases => UpdatedDatabases}; aggregate_use_ctx(Args, _Ctx) -> prepare_use_dir_args(Args). @@ -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). + +-spec is_database_unloaded(binary()) -> boolean(). +is_database_unloaded(DB) -> + mongoose_config:lookup_opt([internal_databases, + binary_to_existing_atom(DB)]) == {error, not_found}. + +-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]), + 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 = <>, - 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. + <>. + +-spec dependency_type_to_string(dependency_type()) -> [string()]. +dependency_type_to_string(Type) -> + string:replace(atom_to_list(Type), "_", " "). + +-spec error_key(dependency_type()) -> atom(). +error_key(Type) -> + list_to_atom("not_loaded_" ++ atom_to_list(Type)). diff --git a/test/mongoose_graphql_SUITE.erl b/test/mongoose_graphql_SUITE.erl index d00cb03f3e..5a79781c3f 100644 --- a/test/mongoose_graphql_SUITE.erl +++ b/test/mongoose_graphql_SUITE.erl @@ -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. @@ -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. @@ -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. @@ -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. @@ -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 := @@ -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 := @@ -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) -> @@ -1244,7 +1229,6 @@ 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, @@ -1252,19 +1236,10 @@ meck_module_and_service_checking(Config) -> % 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().