diff --git a/test/configtest_tests.erl b/test/configtest_tests.erl new file mode 100644 index 000000000..3763b8645 --- /dev/null +++ b/test/configtest_tests.erl @@ -0,0 +1,187 @@ +%%%------------------------------------------------------------------- +%%% Author : Badlop +%%% Created : 5 Feb 2025 by Badlop +%%% +%%% +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne +%%% +%%% This program is free software; you can redistribute it and/or +%%% modify it under the terms of the GNU General Public License as +%%% published by the Free Software Foundation; either version 2 of the +%%% License, or (at your option) any later version. +%%% +%%% This program is distributed in the hope that it will be useful, +%%% but WITHOUT ANY WARRANTY; without even the implied warranty of +%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%%% General Public License for more details. +%%% +%%% You should have received a copy of the GNU General Public License along +%%% with this program; if not, write to the Free Software Foundation, Inc., +%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +%%% +%%%------------------------------------------------------------------- + +-module(configtest_tests). + +-compile(export_all). + +-include("suite.hrl"). + +%%%================================== + +single_cases() -> + {configtest_single, + [sequence], + [single_test(macro_over_keyword), + single_test(keyword_inside_macro), + single_test(macro_and_keyword), + single_test(macro_double), + single_test(keyword_double), + + single_test(macro_toplevel_global_atom), + single_test(macro_toplevel_global_string), + single_test(macro_toplevel_global_string_inside), + single_test(macro_toplevel_local_atom), + single_test(macro_toplevel_local_string), + single_test(macro_toplevel_local_string_inside), + + single_test(keyword_toplevel_global_atom), + single_test(keyword_toplevel_global_string), + single_test(keyword_toplevel_global_string_inside), + single_test(keyword_toplevel_local_atom), + single_test(keyword_toplevel_local_string), + single_test(keyword_toplevel_local_string_inside), + + single_test(macro_module_atom), + single_test(macro_module_string), + single_test(macro_module_string_inside), + + single_test(keyword_module_atom), + single_test(keyword_module_string), + single_test(keyword_module_string_inside), + + single_test(toplevel_global_predefined), + single_test(toplevel_local_predefined), + single_test(module_predefined)]}. + +%% Interactions + +macro_over_keyword(_) -> + toplevel_global(macro, macro_over_keyword). + +keyword_inside_macro(_) -> + toplevel_global(<<"+macro+/-keyword-">>, keyword_inside_macro). + +macro_and_keyword(_) -> + toplevel_global(<<"+macro+&-keyword-">>, macro_and_keyword). + +macro_double(_) -> + toplevel_global(<<"macro--macro">>, macro_double). + +keyword_double(_) -> + toplevel_global(<<"keyword--keyword">>, keyword_double). + +%% Macro Toplevel + +macro_toplevel_global_atom(_) -> + toplevel_global(mtga, mtga). + +macro_toplevel_global_string(_) -> + toplevel_global(<<"Mtgs">>, mtgs). + +macro_toplevel_global_string_inside(_) -> + toplevel_global(<<"Mtgsi">>, mtgsi). + +macro_toplevel_local_atom(_) -> + toplevel_local(mtla, mtla). + +macro_toplevel_local_string(_) -> + toplevel_local(<<"Mtls">>, mtls). + +macro_toplevel_local_string_inside(_) -> + toplevel_local(<<"Mtlsi">>, mtlsi). + +%% Keyword Toplevel + +keyword_toplevel_global_atom(_) -> + toplevel_global(ktga, ktga). + +keyword_toplevel_global_string(_) -> + toplevel_global(<<"Ktgs">>, ktgs). + +keyword_toplevel_global_string_inside(_) -> + toplevel_global(<<"Ktgsi">>, ktgsi). + +keyword_toplevel_local_atom(_) -> + toplevel_local(ktla, ktla). + +keyword_toplevel_local_string(_) -> + toplevel_local(<<"Ktls">>, ktls). + +keyword_toplevel_local_string_inside(_) -> + toplevel_local(<<"Ktlsi">>, ktlsi). + +%% Macro Module + +macro_module_atom(_) -> + module(mma, mma). + +macro_module_string(_) -> + module(<<"Mms">>, mms). + +macro_module_string_inside(_) -> + module(<<"Mmsi">>, mmsi). + +%% Keyword Module + +keyword_module_atom(_) -> + module(kma, kma). + +keyword_module_string(_) -> + module(<<"Kms">>, kms). + +keyword_module_string_inside(_) -> + module(<<"Kmsi">>, kmsi). + +%% Predefined + +toplevel_global_predefined(_) -> + Semver = ejabberd_option:version(), + Version = misc:semver_to_xxyy(Semver), + String = <<"tgp - semver: ", Semver/binary, ", version: ", Version/binary>>, + toplevel_global(String, tgp). + +toplevel_local_predefined(_) -> + Semver = ejabberd_option:version(), + Version = misc:semver_to_xxyy(Semver), + String = <<"tlp - semver: ", Semver/binary, ", version: ", Version/binary>>, + toplevel_local(String, tlp). + +module_predefined(_) -> + Host = <<"configtest.localhost">>, + Semver = ejabberd_option:version(), + Version = misc:semver_to_xxyy(Semver), + String = <<"mp - host: ", Host/binary, ", semver: ", Semver/binary, ", version: ", Version/binary>>, + module(String, predefined_keywords). + +%%%================================== +%%%% internal functions + +single_test(T) -> + list_to_atom("configtest_" ++ atom_to_list(T)). + +toplevel_global(Result, Option) -> + ?match(Result, ejabberd_config:get_option(Option)). + +toplevel_local(Result, Option) -> + Host = <<"configtest.localhost">>, + ?match(Result, ejabberd_config:get_option({Option, Host})). + +module(Result, Option) -> + Host = <<"configtest.localhost">>, + Module = mod_configtest, + ?match(Result, gen_mod:get_module_opt(Host, Module, Option)). + +%%%================================== + +%%% vim: set foldmethod=marker foldmarker=%%%%,%%%=: diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index e240de59b..0a9e73d4d 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -60,6 +60,7 @@ init_per_suite(Config) -> NewConfig. start_ejabberd(_) -> + application:set_env(ejabberd, external_beams, "../../lib/ejabberd/test/"), {ok, _} = application:ensure_all_started(ejabberd, transient). end_per_suite(_Config) -> @@ -398,6 +399,7 @@ no_db_tests() -> auth_external_wrong_server, auth_external_invalid_cert, commands_tests:single_cases(), + configtest_tests:single_cases(), jidprep_tests:single_cases(), sm_tests:single_cases(), sm_tests:master_slave_cases(), diff --git a/test/ejabberd_SUITE_data/configtest.yml b/test/ejabberd_SUITE_data/configtest.yml new file mode 100644 index 000000000..cdd8b0023 --- /dev/null +++ b/test/ejabberd_SUITE_data/configtest.yml @@ -0,0 +1,119 @@ + +define_macro: + CONFIGTEST_CONFIG: + modules: + mod_mam: {} + mod_muc: {} + +## Interactions + +define_macro: + MOK: macro + +define_keyword: + MOK: keyword + +macro_over_keyword: MOK + +## + +define_keyword: + KIM_KEYWORD: "-keyword-" + +define_macro: + KIM_MACRO: "+macro+/@KIM_KEYWORD@" + +keyword_inside_macro: KIM_MACRO + +## + +define_macro: + MAK_MACRO: "+macro+" + +define_keyword: + MAK_KEYWORD: "-keyword-" + +macro_and_keyword: "@MAK_MACRO@&@MAK_KEYWORD@" + +## + +define_macro: + MD: "macro" + +macro_double: "@MD@--@MD@" + +## + +define_keyword: + KD: "keyword" + +keyword_double: "@KD@--@KD@" + +## Macro Toplevel + +define_macro: + MTGA: mtga + MTGS: "Mtgs" + MTLA: mtla + MTLS: "Mtls" + +mtga: MTGA +mtgs: MTGS +mtgsi: "@MTGS@i" + +host_config: + configtest.localhost: + mtla: MTLA + mtls: MTLS + mtlsi: "@MTLS@i" + +## Keyword Toplevel + +define_keyword: + KTGA: ktga + KTLA: ktla + KTGS: "Ktgs" + KTLS: "Ktls" + +ktga: KTGA +ktgs: KTGS +ktgsi: "@KTGS@i" + +host_config: + configtest.localhost: + ktla: KTLA + ktls: KTLS + ktlsi: "@KTLS@i" + +## Macro Module +## Keyword Module +## Predefined Module + +define_macro: + MMA: mma + MMS: "Mms" + +define_keyword: + KMA: kma + KMS: "Kms" + +append_host_config: + configtest.localhost: + modules: + mod_configtest: + mma: MMA + mms: MMS + mmsi: "@MMS@i" + kma: KMA + kms: KMS + kmsi: "@KMS@i" + predefined_keywords: "mp - host: @HOST@, semver: @SEMVER@, version: @VERSION@" + +## Predefined + +tgp: "tgp - semver: @SEMVER@, version: @VERSION@" + +host_config: + configtest.localhost: + tlp: "tlp - semver: @SEMVER@, version: @VERSION@" + diff --git a/test/ejabberd_SUITE_data/ejabberd.yml b/test/ejabberd_SUITE_data/ejabberd.yml index 0155e8f90..e3aa43c3d 100644 --- a/test/ejabberd_SUITE_data/ejabberd.yml +++ b/test/ejabberd_SUITE_data/ejabberd.yml @@ -1,5 +1,6 @@ include_config_file: - macros.yml + - configtest.yml - ejabberd.extauth.yml - ejabberd.ldap.yml - ejabberd.mnesia.yml @@ -10,6 +11,7 @@ include_config_file: - ejabberd.sqlite.yml host_config: + configtest.localhost: CONFIGTEST_CONFIG pgsql.localhost: PGSQL_CONFIG sqlite.localhost: SQLITE_CONFIG mysql.localhost: MYSQL_CONFIG @@ -25,6 +27,7 @@ host_config: hosts: - localhost + - configtest.localhost - mnesia.localhost - redis.localhost - mysql.localhost diff --git a/test/ejabberd_test_options.erl b/test/ejabberd_test_options.erl new file mode 100644 index 000000000..10cfcab3e --- /dev/null +++ b/test/ejabberd_test_options.erl @@ -0,0 +1,114 @@ +%%%---------------------------------------------------------------------- +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne +%%% +%%% This program is free software; you can redistribute it and/or +%%% modify it under the terms of the GNU General Public License as +%%% published by the Free Software Foundation; either version 2 of the +%%% License, or (at your option) any later version. +%%% +%%% This program is distributed in the hope that it will be useful, +%%% but WITHOUT ANY WARRANTY; without even the implied warranty of +%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%%% General Public License for more details. +%%% +%%% You should have received a copy of the GNU General Public License along +%%% with this program; if not, write to the Free Software Foundation, Inc., +%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +%%% +%%%---------------------------------------------------------------------- +-module(ejabberd_test_options). +-behaviour(ejabberd_config). + +-export([opt_type/1, options/0, globals/0, doc/0]). + +%%%=================================================================== +%%% API +%%%=================================================================== +-spec opt_type(atom()) -> econf:validator(). + +opt_type(macro_over_keyword) -> + econf:atom(); + +opt_type(keyword_inside_macro) -> + econf:binary(); + +opt_type(macro_and_keyword) -> + econf:binary(); + +opt_type(macro_double) -> + econf:binary(); + +opt_type(keyword_double) -> + econf:binary(); + +opt_type(mtga) -> + econf:atom(); + +opt_type(mtgs) -> + econf:binary(); + +opt_type(mtgsi) -> + econf:binary(); + +opt_type(mtla) -> + econf:atom(); + +opt_type(mtls) -> + econf:binary(); + +opt_type(mtlsi) -> + econf:binary(); + +opt_type(ktga) -> + econf:atom(); + +opt_type(ktgs) -> + econf:binary(); + +opt_type(ktgsi) -> + econf:binary(); + +opt_type(ktla) -> + econf:atom(); + +opt_type(ktls) -> + econf:binary(); + +opt_type(ktlsi) -> + econf:binary(); + +opt_type(tgp) -> + econf:binary(); + +opt_type(tlp) -> + econf:binary(). + +options() -> + [{macro_over_keyword, undefined}, + {keyword_inside_macro, undefined}, + {macro_and_keyword, undefined}, + {macro_double, undefined}, + {keyword_double, undefined}, + {mtga, undefined}, + {mtgs, undefined}, + {mtgsi, undefined}, + {mtla, undefined}, + {mtls, undefined}, + {mtlsi, undefined}, + {ktga, undefined}, + {ktgs, undefined}, + {ktgsi, undefined}, + {ktla, undefined}, + {ktls, undefined}, + {ktlsi, undefined}, + {tgp, undefined}, + {tlp, undefined} + ]. + +-spec globals() -> [atom()]. +globals() -> + []. + +doc() -> + ejabberd_options_doc:doc(). + diff --git a/test/mod_configtest.erl b/test/mod_configtest.erl new file mode 100644 index 000000000..a4ca36f33 --- /dev/null +++ b/test/mod_configtest.erl @@ -0,0 +1,45 @@ +-module(mod_configtest). +-behaviour(gen_mod). + +-export([start/2, stop/1, reload/3, mod_opt_type/1, mod_options/1, depends/2, mod_doc/0]). + +start(_Host, _Opts) -> + ok. + +stop(_Host) -> + ok. + +reload(_Host, _NewOpts, _OldOpts) -> + ok. + +depends(_Host, _Opts) -> + []. + +mod_opt_type(mma) -> + econf:atom(); +mod_opt_type(mms) -> + econf:binary(); +mod_opt_type(mmsi) -> + econf:binary(); + +mod_opt_type(kma) -> + econf:atom(); +mod_opt_type(kms) -> + econf:binary(); +mod_opt_type(kmsi) -> + econf:binary(); + +mod_opt_type(predefined_keywords) -> + econf:binary(). + +mod_options(_) -> + [{mma, undefined}, + {mms, undefined}, + {mmsi, undefined}, + {kma, undefined}, + {kms, undefined}, + {kmsi, undefined}, + {predefined_keywords, undefined}]. + +mod_doc() -> + #{}. diff --git a/test/suite.erl b/test/suite.erl index 0066b5116..28825b1d1 100644 --- a/test/suite.erl +++ b/test/suite.erl @@ -84,6 +84,7 @@ init_config(Config) -> {priv_dir, PrivDir}]), MacrosPath = filename:join([CWD, "macros.yml"]), ok = file:write_file(MacrosPath, MacrosContent), + copy_configtest_yml(DataDir, CWD), copy_backend_configs(DataDir, CWD, Backends), setup_ejabberd_lib_path(Config), case application:load(sasl) of @@ -137,11 +138,32 @@ init_config(Config) -> {backends, Backends} |Config]. +copy_configtest_yml(DataDir, CWD) -> + Files = filelib:wildcard(filename:join([DataDir, "configtest.yml"])), + lists:foreach( + fun(Src) -> + ct:pal("copying ~p", [Src]), + File = filename:basename(Src), + case string:tokens(File, ".") of + ["configtest", "yml"] -> + Dst = filename:join([CWD, File]), + case true of + true -> + {ok, _} = file:copy(Src, Dst); + false -> + ok + end; + _ -> + ok + end + end, Files). + + copy_backend_configs(DataDir, CWD, Backends) -> Files = filelib:wildcard(filename:join([DataDir, "ejabberd.*.yml"])), lists:foreach( fun(Src) -> - io:format("copying ~p", [Src]), + ct:pal("copying ~p", [Src]), File = filename:basename(Src), case string:tokens(File, ".") of ["ejabberd", SBackend, "yml"] ->