1: -module(mongoose_config_SUITE).
    2: -compile([export_all, nowarn_export_all]).
    3: 
    4: -include_lib("common_test/include/ct.hrl").
    5: -include_lib("eunit/include/eunit.hrl").
    6: 
    7: -import(ejabberd_helper, [start_ejabberd/1,
    8:                           start_ejabberd_with_config/2,
    9:                           stop_ejabberd/0,
   10:                           use_config_file/2,
   11:                           copy/2,
   12:                           data/2]).
   13: 
   14: all() ->
   15:     [get_opt,
   16:      lookup_opt,
   17:      load_from_file,
   18:      {group, cluster}].
   19: 
   20: groups() ->
   21:     [
   22:      {cluster, [], [cluster_load_from_file]}
   23:     ].
   24: 
   25: init_per_suite(Config) ->
   26:     {ok, _} = application:ensure_all_started(jid),
   27:     Config.
   28: 
   29: end_per_suite(_Config) ->
   30:     [persistent_term:erase(Key) || {Key = {mongoose_config, _}, _Value} <- persistent_term:get()],
   31:     persistent_term:erase(mongoose_config_state),
   32:     mnesia:stop(),
   33:     mnesia:delete_schema([node()]),
   34:     ok.
   35: 
   36: init_per_testcase(_TestCase, Config) ->
   37:     Config.
   38: 
   39: end_per_testcase(_TestCase, _Config) ->
   40:     ok.
   41: 
   42: init_per_group(cluster, Config) ->
   43:     start_slave_node(Config);
   44: init_per_group(_GroupName, Config) ->
   45:     Config.
   46: 
   47: end_per_group(cluster, Config) ->
   48:     stop_slave_node(Config),
   49:     ok;
   50: end_per_group(_GroupName, _Config) ->
   51:     ok.
   52: 
   53: %%
   54: %% Tests
   55: %%
   56: 
   57: get_opt(_Config) ->
   58:     ?assertError(badarg, mongoose_config:get_opt(get_me)),
   59:     ?assertEqual(default_value, mongoose_config:get_opt(get_me, default_value)),
   60:     mongoose_config:set_opt(get_me, you_got_me),
   61:     ?assertEqual(you_got_me, mongoose_config:get_opt(get_me)),
   62:     mongoose_config:set_opt(get_me, you_got_me_again),
   63:     ?assertEqual(you_got_me_again, mongoose_config:get_opt(get_me)),
   64:     ?assertEqual(you_got_me_again, mongoose_config:get_opt(get_me, default_value)),
   65:     mongoose_config:unset_opt(get_me),
   66:     ?assertError(badarg, mongoose_config:get_opt(get_me)),
   67:     ?assertEqual(default_value, mongoose_config:get_opt(get_me, default_value)).
   68: 
   69: lookup_opt(_Config) ->
   70:     ?assertEqual({error, not_found}, mongoose_config:lookup_opt(look_me_up)),
   71:     mongoose_config:set_opt(look_me_up, here_i_am),
   72:     ?assertEqual({ok, here_i_am}, mongoose_config:lookup_opt(look_me_up)),
   73:     mongoose_config:unset_opt(look_me_up),
   74:     ?assertEqual({error, not_found}, mongoose_config:lookup_opt(look_me_up)).
   75: 
   76: load_from_file(Config) ->
   77:     use_config_file(Config, "mongooseim.minimal.toml"),
   78:     ok = mongoose_config:start(),
   79:     State = mongoose_config:config_state(),
   80:     check_loaded_config(State),
   81: 
   82:     ok = mongoose_config:stop(),
   83:     check_removed_config(),
   84: 
   85:     %% Try to stop it again
   86:     {error, not_started} = mongoose_config:stop().
   87: 
   88: cluster_load_from_file(Config) ->
   89:     SlaveNode = slave_node(Config),
   90:     copy(data(Config, "mongooseim.minimal.toml"), data(Config, "mongooseim.toml")),
   91: 
   92:     %% Start clustered MongooseIM and check the loaded config
   93:     {ok, _} = start_ejabberd_with_config(Config, "mongooseim.toml"),
   94:     {ok, _} = start_remote_ejabberd_with_config(SlaveNode, Config, "mongooseim.toml"),
   95:     maybe_join_cluster(SlaveNode),
   96:     [State, State] = mongoose_config:config_states(),
   97:     check_loaded_config(State),
   98: 
   99:     ok = stop_ejabberd(),
  100:     stop_remote_ejabberd(SlaveNode),
  101:     check_removed_config().
  102: 
  103: %%
  104: %% Helpers
  105: %%
  106: 
  107: check_loaded_config(State) ->
  108:     Opts = lists:sort(mongoose_config_parser:state_to_opts(State)),
  109:     ExpectedOpts = lists:sort(minimal_config_opts()),
  110:     ?assertEqual(ExpectedOpts, Opts),
  111:     [?assertEqual(Val, mongoose_config:get_opt(Key)) || {Key, Val} <- ExpectedOpts].
  112: 
  113: check_removed_config() ->
  114:     Opts = minimal_config_opts(),
  115:     ?assertError(badarg, mongoose_config:config_state()),
  116:     [?assertError(badarg, mongoose_config:get_opt(Key)) || {Key, _} <- Opts].
  117: 
  118: minimal_config_opts() ->
  119:     [{all_metrics_are_global, false},
  120:      {default_server_domain, <<"localhost">>},
  121:      {hide_service_name, false},
  122:      {host_types, []},
  123:      {hosts, [<<"localhost">>]},
  124:      {language, <<"en">>},
  125:      {loglevel, warning},
  126:      {mongooseimctl_access_commands, []},
  127:      {rdbms_server_type, generic},
  128:      {registration_timeout, 600},
  129:      {routing_modules, [mongoose_router_global,
  130:                         mongoose_router_localdomain,
  131:                         mongoose_router_external_localnode,
  132:                         mongoose_router_external,
  133:                         mongoose_router_dynamic_domains,
  134:                         ejabberd_s2s]},
  135:      {sm_backend, {mnesia, []}},
  136:      {{replaced_wait_timeout, <<"localhost">>}, 2000}].
  137: 
  138: start_slave_node(Config) ->
  139:     SlaveNode = do_start_slave_node(),
  140:     [{slave_node, SlaveNode}|Config].
  141: 
  142: do_start_slave_node() ->
  143:     Opts = [{monitor_master, true},
  144:             {boot_timeout, 15}, %% in seconds
  145:             {init_timeout, 10}, %% in seconds
  146:             {startup_timeout, 10}], %% in seconds
  147:     {ok, SlaveNode} = ct_slave:start(slave_name(), Opts),
  148:     {ok, CWD} = file:get_cwd(),
  149:     ok = rpc:call(SlaveNode, file, set_cwd, [CWD]),
  150:     %% Tell the remote node where to find the SUITE code
  151:     %% Be aware, that P1 likes to put there stuff into
  152:     %% /usr/lib/erlang/lib/
  153:     %% So add_paths is NOT enough here
  154:     ok = rpc:call(SlaveNode, code, add_pathsa, [lists:reverse(code_paths())]),
  155:     check_that_p1_tls_is_correct(SlaveNode),
  156:     SlaveNode.
  157: 
  158: check_that_p1_tls_is_correct(SlaveNode) ->
  159:     ?assertEqual(fast_tls:module_info(md5),
  160:                  rpc:call(SlaveNode, fast_tls, module_info, [md5])).
  161: 
  162: stop_slave_node(Config) ->
  163:     ct_slave:stop(slave_node(Config)),
  164:     ok.
  165: 
  166: slave_node(Config) ->
  167:     get_required_config(slave_node, Config).
  168: 
  169: get_required_config(Key, Config) ->
  170:     case proplists:get_value(Key, Config) of
  171:         undefined ->
  172:             ct:fail({get_required_config_failed, Key});
  173:         Value ->
  174:             Value
  175:     end.
  176: 
  177: slave_name() ->
  178:     'mim_slave'.
  179: 
  180: start_remote_ejabberd_with_config(RemoteNode, C, ConfigFile) ->
  181:     rpc:call(RemoteNode, ejabberd_helper, start_ejabberd_with_config, [C, ConfigFile]).
  182: 
  183: stop_remote_ejabberd(SlaveNode) ->
  184:     rpc:call(SlaveNode, ejabberd_helper, stop_ejabberd, []).
  185: 
  186: code_paths() ->
  187:     [filename:absname(Path) || Path <- code:get_path()].
  188: 
  189: maybe_join_cluster(SlaveNode) ->
  190:     Result = rpc:call(SlaveNode, ejabberd_admin, join_cluster,
  191:                       [atom_to_list(node())]),
  192:     case Result of
  193:         {ok, _} ->
  194:             ok;
  195:         {already_joined, _} ->
  196:             ok
  197:     end.
  198: