1: -module(persistent_cluster_id_SUITE).
    2: 
    3: -include_lib("common_test/include/ct.hrl").
    4: -include_lib("eunit/include/eunit.hrl").
    5: 
    6: %% API
    7: -export([all/0,
    8:          groups/0,
    9:          init_per_suite/1,
   10:          end_per_suite/1,
   11:          group/1,
   12:          init_per_group/2,
   13:          end_per_group/2,
   14:          init_per_testcase/2,
   15:          end_per_testcase/2]).
   16: 
   17: %% test cases
   18: -export([
   19:          all_nodes_in_the_cluster_have_the_same_cluster_id/1,
   20:          id_persists_after_restart/1,
   21:          same_cluster_id_in_backend_and_mnesia/1,
   22:          backed_up_id_if_rdbms_is_added/1,
   23:          cluster_id_is_restored_to_mnesia_from_rdbms_if_mnesia_lost/1,
   24:          clean_start_and_two_nodes/1
   25:         ]).
   26: 
   27: -import(distributed_helper, [mim/0, mim2/0]).
   28: 
   29: -import(domain_helper, [host_type/0]).
   30: 
   31: all() ->
   32:     [
   33:      {group, mnesia},
   34:      {group, rdbms}
   35:     ].
   36: 
   37: tests() ->
   38:     [
   39:      all_nodes_in_the_cluster_have_the_same_cluster_id,
   40:      id_persists_after_restart,
   41:      same_cluster_id_in_backend_and_mnesia,
   42:      backed_up_id_if_rdbms_is_added,
   43:      cluster_id_is_restored_to_mnesia_from_rdbms_if_mnesia_lost,
   44:      clean_start_and_two_nodes
   45:     ].
   46: 
   47: groups() ->
   48:     [
   49:      {mnesia, [], [all_nodes_in_the_cluster_have_the_same_cluster_id]},
   50:      {rdbms, [], tests()}
   51:     ].
   52: 
   53: %%%===================================================================
   54: %%% Overall setup/teardown
   55: %%%===================================================================
   56: init_per_suite(Config) ->
   57:     distributed_helper:require_rpc_nodes([mim]) ++ Config.
   58: 
   59: end_per_suite(_Config) ->
   60:     ok.
   61: 
   62: %%%===================================================================
   63: %%% Group specific setup/teardown
   64: %%%===================================================================
   65: group(_Groupname) ->
   66:     [].
   67: 
   68: init_per_group(mnesia, Config) ->
   69:     case not mongoose_helper:is_rdbms_enabled(host_type()) of
   70:         true -> Config;
   71:         false -> {skip, require_no_rdbms}
   72:     end;
   73: init_per_group(_Groupname, Config) ->
   74:     case mongoose_helper:is_rdbms_enabled(host_type()) of
   75:         true -> Config;
   76:         false -> {skip, require_rdbms}
   77:     end.
   78: 
   79: end_per_group(_Groupname, _Config) ->
   80:     ok.
   81: 
   82: %%%===================================================================
   83: %%% Testcase specific setup/teardown
   84: %%%===================================================================
   85: init_per_testcase(all_nodes_in_the_cluster_have_the_same_cluster_id, Config) ->
   86:     distributed_helper:add_node_to_cluster(mim2(), Config),
   87:     Config;
   88: init_per_testcase(_TestCase, Config) ->
   89:     Config.
   90: 
   91: end_per_testcase(all_nodes_in_the_cluster_have_the_same_cluster_id, Config) ->
   92:     distributed_helper:remove_node_from_cluster(mim2(), Config),
   93:     Config;
   94: end_per_testcase(_TestCase, _Config) ->
   95:     ok.
   96: 
   97: %%%===================================================================
   98: %%% Individual Test Cases (from groups() definition)
   99: %%%===================================================================
  100: all_nodes_in_the_cluster_have_the_same_cluster_id(_Config) ->
  101:     {ok, ID_mim1} = mongoose_helper:successful_rpc(
  102:                mim(), mongoose_cluster_id, get_cached_cluster_id, []),
  103:     {ok, ID_mim2} = mongoose_helper:successful_rpc(
  104:                mim2(), mongoose_cluster_id, get_cached_cluster_id, []),
  105:     ?assertEqual(ID_mim1, ID_mim2).
  106: 
  107: id_persists_after_restart(_Config) ->
  108:     {ok, FirstID} = mongoose_helper:successful_rpc(
  109:                mim(), mongoose_cluster_id, get_cached_cluster_id, []),
  110:     ejabberd_node_utils:restart_application(mongooseim),
  111:     {ok, SecondID} = mongoose_helper:successful_rpc(
  112:                mim(), mongoose_cluster_id, get_cached_cluster_id, []),
  113:     ?assertEqual(FirstID, SecondID).
  114: 
  115: same_cluster_id_in_backend_and_mnesia(_Config) ->
  116:     {ok, MnesiaID} = mongoose_helper:successful_rpc(
  117:                mim(), mongoose_cluster_id, get_cached_cluster_id, []),
  118:     {ok, BackendID} = mongoose_helper:successful_rpc(
  119:                mim(), mongoose_cluster_id, get_backend_cluster_id, []),
  120:     ?assertEqual(MnesiaID, BackendID).
  121: 
  122: backed_up_id_if_rdbms_is_added(_Config) ->
  123:     ok = mongoose_helper:successful_rpc(
  124:            mim(), mongoose_cluster_id, clean_table, []),
  125:     {ok, MnesiaID} = mongoose_helper:successful_rpc(
  126:            mim(), mongoose_cluster_id, get_cached_cluster_id, []),
  127:     {error, no_value_in_backend} = mongoose_helper:successful_rpc(
  128:            mim(), mongoose_cluster_id, get_backend_cluster_id, []),
  129:     {ok, AfterRestartID} = mongoose_helper:successful_rpc(
  130:            mim(), mongoose_cluster_id, start, []),
  131:     {ok, BackendID} = mongoose_helper:successful_rpc(
  132:            mim(), mongoose_cluster_id, get_backend_cluster_id, []),
  133:     ?assertEqual(AfterRestartID, MnesiaID),
  134:     ?assertEqual(AfterRestartID, BackendID).
  135: 
  136: cluster_id_is_restored_to_mnesia_from_rdbms_if_mnesia_lost(_Config) ->
  137:     {ok, FirstID} = mongoose_helper:successful_rpc(
  138:                mim(), mongoose_cluster_id, get_cached_cluster_id, []),
  139:     %% mongoose_cluster:leave/0 does everything we need here:
  140:     %%  it stops the node, deletes everything related to mnesia from the system,
  141:     %%  the hardcore way, removing folders from the OS and so on, and restarts the node.
  142:     %%  Assuming this works correctly, then we can be sure that "mnesia files were lost".
  143:     Node = mim(),
  144:     ok = distributed_helper:rpc(
  145:            Node#{timeout => timer:seconds(30)}, mongoose_cluster, leave, []),
  146:     {ok, SecondID} = mongoose_helper:successful_rpc(
  147:                Node, mongoose_cluster_id, get_cached_cluster_id, []),
  148:     ?assertEqual(FirstID, SecondID).
  149: 
  150: clean_start_and_two_nodes(_Config) ->
  151:     {ok, MnesiaID} = mongoose_helper:successful_rpc(
  152:            mim(), mongoose_cluster_id, get_cached_cluster_id, []),
  153:     {ok, MnesiaID2} = mongoose_helper:successful_rpc(
  154:            mim2(), mongoose_cluster_id, get_cached_cluster_id, []),
  155:     %% Sanity check: IDs are in sync
  156:     ?assertEqual(MnesiaID, MnesiaID2),
  157:     %% Remove an old ID from anywhere
  158:     ok = mongoose_helper:successful_rpc(
  159:            mim(), mongoose_cluster_id, clean_table, []),
  160:     ok = mongoose_helper:successful_rpc(
  161:            mim(), mongoose_cluster_id, clean_cache, []),
  162:     ok = mongoose_helper:successful_rpc(
  163:            mim2(), mongoose_cluster_id, clean_cache, []),
  164:     {ok, AfterRestartID} = mongoose_helper:successful_rpc(
  165:            mim(), mongoose_cluster_id, start, []),
  166:     {ok, AfterRestartID2} = mongoose_helper:successful_rpc(
  167:            mim2(), mongoose_cluster_id, start, []),
  168:     %% We've created a new ID
  169:     ?assertNotEqual(AfterRestartID, MnesiaID),
  170:     %% Both nodes have the same ID
  171:     ?assertEqual(AfterRestartID, AfterRestartID2).