1: -module(graphql_server_SUITE). 2: 3: -compile([export_all, nowarn_export_all]). 4: 5: -import(distributed_helper, [is_sm_distributed/0, 6: mim/0, mim2/0, mim3/0, 7: remove_node_from_cluster/2, 8: require_rpc_nodes/1, rpc/4]). 9: -import(domain_helper, [host_type/0, domain/0]). 10: -import(graphql_helper, [execute_user_command/5, execute_command/4, get_ok_value/2, 11: get_err_msg/1, get_err_code/1, execute_command/5]). 12: 13: -include_lib("eunit/include/eunit.hrl"). 14: 15: suite() -> 16: require_rpc_nodes([mim]) ++ escalus:suite(). 17: 18: all() -> 19: [{group, admin_http}, 20: {group, admin_cli}]. 21: 22: groups() -> 23: [{admin_http, [], admin_http_groups()}, 24: {admin_cli, [], admin_cli_groups()}, 25: {server_tests, [], admin_tests()}, 26: {clustering_tests, [], clustering_tests()}, 27: {clustering_http_tests, [], clustering_http_tests()}]. 28: 29: admin_cli_groups() -> 30: [{group, server_tests}, 31: {group, clustering_tests}]. 32: 33: admin_http_groups() -> 34: [{group, server_tests}, 35: {group, clustering_http_tests}]. 36: 37: admin_tests() -> 38: [get_cookie_test, 39: set_and_get_loglevel_test, 40: get_status_test]. 41: 42: clustering_tests() -> 43: [join_successful, 44: leave_successful, 45: join_unsuccessful, 46: leave_but_no_cluster, 47: join_twice, 48: leave_twice, 49: remove_dead_from_cluster, 50: remove_alive_from_cluster, 51: remove_node_test, 52: stop_node_test]. 53: 54: clustering_http_tests() -> 55: [join_successful_http, 56: leave_successful_http, 57: remove_dead_from_cluster_http, 58: remove_alive_from_cluster_http, 59: remove_node_test, 60: stop_node_test]. 61: 62: init_per_suite(Config) -> 63: Config1 = dynamic_modules:save_modules(host_type(), Config), 64: Config2 = lists:foldl(fun(#{node := Node} = RPCNode, ConfigAcc) -> 65: ConfigAcc1 = ejabberd_node_utils:init(RPCNode, ConfigAcc), 66: NodeCtlPath = distributed_helper:ctl_path(Node, ConfigAcc1), 67: ConfigAcc1 ++ [{ctl_path_atom(Node), NodeCtlPath}] 68: end, Config1, [mim(), mim2(), mim3()]), 69: escalus:init_per_suite(Config2). 70: 71: ctl_path_atom(NodeName) -> 72: CtlString = atom_to_list(NodeName) ++ "_ctl", 73: list_to_atom(CtlString). 74: 75: end_per_suite(Config) -> 76: dynamic_modules:restore_modules(Config), 77: escalus:end_per_suite(Config). 78: 79: init_per_group(admin_http, Config) -> 80: graphql_helper:init_admin_handler(Config); 81: init_per_group(admin_cli, Config) -> 82: graphql_helper:init_admin_cli(Config); 83: init_per_group(Group, Config) when Group =:= clustering_tests; Group =:= clustering_http_tests -> 84: case is_sm_distributed() of 85: true -> 86: Config; 87: {false, Backend} -> 88: ct:pal("Backend ~p doesn't support distributed tests", [Backend]), 89: {skip, nondistributed_sm} 90: end; 91: init_per_group(_, Config) -> 92: Config. 93: 94: end_per_group(Group, _Config) when Group =:= admin_http; 95: Group =:= admin_cli -> 96: graphql_helper:clean(); 97: end_per_group(_, _Config) -> 98: escalus_fresh:clean(). 99: 100: init_per_testcase(set_and_get_loglevel_test = CaseName, Config) -> 101: Config1 = mim_loglevel:save_log_level(Config), 102: escalus:init_per_testcase(CaseName, Config1); 103: init_per_testcase(CaseName, Config) -> 104: escalus:init_per_testcase(CaseName, Config). 105: 106: 107: end_per_testcase(set_and_get_loglevel_test = CaseName, Config) -> 108: mim_loglevel:restore_log_level(Config), 109: escalus:end_per_testcase(CaseName, Config); 110: end_per_testcase(CaseName, Config) when CaseName == join_successful 111: orelse CaseName == join_successful_http 112: orelse CaseName == join_twice 113: orelse CaseName == leave_twice -> 114: remove_node_from_cluster(mim2(), Config), 115: escalus:end_per_testcase(CaseName, Config); 116: end_per_testcase(CaseName, Config) when CaseName == remove_alive_from_cluster 117: orelse CaseName == remove_dead_from_cluster 118: orelse CaseName == remove_alive_from_cluster_http 119: orelse CaseName == remove_dead_from_cluster_http -> 120: remove_node_from_cluster(mim2(), Config), 121: remove_node_from_cluster(mim3(), Config), 122: escalus:end_per_testcase(CaseName, Config); 123: end_per_testcase(CaseName, Config) -> 124: escalus:end_per_testcase(CaseName, Config). 125: 126: get_cookie_test(Config) -> 127: Result = get_ok_value([data, server, getCookie], get_cookie(Config)), 128: ?assert(is_binary(Result)). 129: 130: set_and_get_loglevel_test(Config) -> 131: LogLevels = all_log_levels(), 132: lists:foreach(fun(LogLevel) -> 133: Value = get_ok_value([data, server, setLoglevel], set_loglevel(LogLevel, Config)), 134: ?assertEqual(<<"Log level successfully set.">>, Value), 135: Value1 = get_ok_value([data, server, getLoglevel], get_loglevel(Config)), 136: ?assertEqual(LogLevel, Value1) 137: end, LogLevels), 138: {_, Res} = set_loglevel(<<"AAAA">>, Config), 139: [Res1] = maps:get(<<"errors">>, Res), 140: ?assertEqual(<<"unknown_enum">>, graphql_helper:get_value([extensions, code], Res1)). 141: 142: get_status_test(Config) -> 143: Result = get_ok_value([data, server, status], get_status(Config)), 144: ?assertEqual(<<"RUNNING">>, maps:get(<<"statusCode">>, Result)), 145: ?assert(is_binary(maps:get(<<"message">>, Result))), 146: ?assert(is_binary(maps:get(<<"version">>, Result))), 147: ?assert(is_binary(maps:get(<<"commitHash">>, Result))). 148: 149: 150: join_successful(Config) -> 151: #{node := Node2} = RPCSpec2 = mim2(), 152: leave_cluster(Config), 153: get_ok_value([], join_cluster(atom_to_binary(Node2), Config)), 154: distributed_helper:verify_result(RPCSpec2, add). 155: 156: leave_successful(Config) -> 157: #{node := Node2} = RPCSpec2 = mim2(), 158: join_cluster(atom_to_binary(Node2), Config), 159: get_ok_value([], leave_cluster(Config)), 160: distributed_helper:verify_result(RPCSpec2, remove). 161: 162: join_unsuccessful(Config) -> 163: Node2 = mim2(), 164: join_cluster(<<>>, Config), 165: distributed_helper:verify_result(Node2, remove). 166: 167: leave_but_no_cluster(Config) -> 168: Node2 = mim2(), 169: get_err_code(leave_cluster(Config)), 170: distributed_helper:verify_result(Node2, remove). 171: 172: join_twice(Config) -> 173: #{node := Node2} = RPCSpec2 = mim2(), 174: get_ok_value([], join_cluster(atom_to_binary(Node2), Config)), 175: ?assertEqual(<<"already_joined">>, get_err_code(join_cluster(atom_to_binary(Node2), Config))), 176: distributed_helper:verify_result(RPCSpec2, add). 177: 178: leave_twice(Config) -> 179: #{node := Node2} = RPCSpec2 = mim2(), 180: join_cluster(atom_to_binary(Node2), Config), 181: get_ok_value([], leave_cluster(Config)), 182: distributed_helper:verify_result(RPCSpec2, remove), 183: ?assertEqual(<<"not_in_cluster">>, get_err_code(leave_cluster(Config))). 184: 185: remove_dead_from_cluster(Config) -> 186: % given 187: Timeout = timer:seconds(60), 188: #{node := Node1Nodename} = Node1 = mim(), 189: #{node := _Node2Nodename} = Node2 = mim2(), 190: #{node := Node3Nodename} = Node3 = mim3(), 191: ok = rpc(Node2#{timeout => Timeout}, mongoose_cluster, join, [Node1Nodename]), 192: ok = rpc(Node3#{timeout => Timeout}, mongoose_cluster, join, [Node1Nodename]), 193: %% when 194: distributed_helper:stop_node(Node3Nodename, Config), 195: get_ok_value([data, server, removeFromCluster], 196: remove_from_cluster(atom_to_binary(Node3Nodename), Config)), 197: %% then 198: % node is down hence its not in mnesia cluster 199: have_node_in_mnesia_wait(Node1, Node2, true), 200: have_node_in_mnesia_wait(Node1, Node3, false), 201: have_node_in_mnesia_wait(Node2, Node3, false), 202: % after node awakening nodes are clustered again 203: distributed_helper:start_node(Node3Nodename, Config), 204: have_node_in_mnesia_wait(Node1, Node3, true), 205: have_node_in_mnesia_wait(Node2, Node3, true). 206: 207: remove_alive_from_cluster(Config) -> 208: % given 209: Timeout = timer:seconds(60), 210: #{node := Node1Name} = Node1 = mim(), 211: #{node := Node2Name} = Node2 = mim2(), 212: Node3 = mim3(), 213: ok = rpc(Node2#{timeout => Timeout}, mongoose_cluster, join, [Node1Name]), 214: ok = rpc(Node3#{timeout => Timeout}, mongoose_cluster, join, [Node1Name]), 215: %% when 216: %% Node2 is still running 217: %% then 218: get_ok_value([], remove_from_cluster(atom_to_binary(Node2Name), Config)), 219: have_node_in_mnesia(Node1, Node3, true), 220: have_node_in_mnesia(Node1, Node2, false), 221: have_node_in_mnesia(Node3, Node2, false). 222: 223: remove_node_test(Config) -> 224: #{node := NodeName} = mim3(), 225: Value = get_ok_value([data, server, removeNode], remove_node(NodeName, Config)), 226: ?assertEqual(<<"MongooseIM node removed from the Mnesia schema">>, Value). 227: 228: stop_node_test(Config) -> 229: #{node := Node3Nodename} = mim3(), 230: get_ok_value([data, server, stop], stop_node(Node3Nodename, Config)), 231: Timeout = timer:seconds(3), 232: F = fun() -> rpc:call(Node3Nodename, application, which_applications, [], Timeout) end, 233: mongoose_helper:wait_until(F, {badrpc, nodedown}, #{sleep_time => 1000, name => stop_node}), 234: distributed_helper:start_node(Node3Nodename, Config). 235: 236: join_successful_http(Config) -> 237: #{node := Node2} = RPCSpec2 = mim2(), 238: leave_cluster(Config), 239: distributed_helper:verify_result(RPCSpec2, remove), 240: get_ok_value([], join_cluster(atom_to_binary(Node2), Config)), 241: distributed_helper:verify_result(RPCSpec2, add). 242: 243: leave_successful_http(Config) -> 244: #{node := Node2} = RPCSpec2 = mim2(), 245: join_cluster(atom_to_binary(Node2), Config), 246: distributed_helper:verify_result(RPCSpec2, add), 247: get_ok_value([], leave_cluster(Config)), 248: distributed_helper:verify_result(RPCSpec2, remove). 249: 250: remove_dead_from_cluster_http(Config) -> 251: % given 252: Timeout = timer:seconds(60), 253: #{node := Node1Nodename} = Node1 = mim(), 254: #{node := _Node2Nodename} = Node2 = mim2(), 255: #{node := Node3Nodename} = Node3 = mim3(), 256: ok = rpc(Node2#{timeout => Timeout}, mongoose_cluster, join, [Node1Nodename]), 257: ok = rpc(Node3#{timeout => Timeout}, mongoose_cluster, join, [Node1Nodename]), 258: %% when 259: distributed_helper:stop_node(Node3Nodename, Config), 260: F2 = fun() -> 261: test == rpc(Node1#{timeout => Timeout}, mongoose_config, get_opt, [listen, test]) 262: end, 263: mongoose_helper:wait_until(F2, false, #{sleep_time => 200, name => wait_for_mim1, 264: time_left => timer:seconds(20)}), 265: get_ok_value([data, server, removeFromCluster], 266: remove_from_cluster(atom_to_binary(Node3Nodename), Config)), 267: have_node_in_mnesia_wait(Node1, Node2, true), 268: have_node_in_mnesia_wait(Node1, Node3, false), 269: have_node_in_mnesia_wait(Node2, Node3, false), 270: % after node awakening nodes are clustered again 271: distributed_helper:start_node(Node3Nodename, Config), 272: ensure_node_started(Node3), 273: have_node_in_mnesia_wait(Node1, Node3, true), 274: have_node_in_mnesia_wait(Node2, Node3, true). 275: 276: remove_alive_from_cluster_http(Config) -> 277: % given 278: Timeout = timer:seconds(60), 279: #{node := Node1Name} = Node1 = mim(), 280: #{node := Node2Name} = Node2 = mim2(), 281: Node3 = mim3(), 282: ok = rpc(Node2#{timeout => Timeout}, mongoose_cluster, join, [Node1Name]), 283: ok = rpc(Node3#{timeout => Timeout}, mongoose_cluster, join, [Node1Name]), 284: %% when 285: %% Node2 is still running 286: %% then 287: get_ok_value([], remove_from_cluster(atom_to_binary(Node2Name), Config)), 288: have_node_in_mnesia_wait(Node1, Node3, true), 289: have_node_in_mnesia_wait(Node1, Node2, false), 290: have_node_in_mnesia_wait(Node3, Node2, false). 291: 292: ensure_node_started(Node) -> 293: Timeout = timer:seconds(60), 294: F = fun() -> 295: case rpc(Node#{timeout => Timeout}, mongoose_server_api, status, []) of 296: {ok, {true, _, _, _}} -> true; 297: _Other -> false 298: end 299: end, 300: mongoose_helper:wait_until(F, true, #{sleep_time => 200, name => wait_for_start_mim3, 301: time_left => timer:seconds(20)}). 302: 303: %----------------------------------------------------------------------- 304: % Helpers 305: %----------------------------------------------------------------------- 306: 307: have_node_in_mnesia_wait(Node1, #{node := Node2}, Value) -> 308: mongoose_helper:wait_until(fun() -> 309: DbNodes1 = distributed_helper:rpc(Node1, mnesia, 310: system_info, [db_nodes]), 311: lists:member(Node2, DbNodes1) 312: end, 313: Value, 314: #{ 315: time_left => timer:seconds(12), 316: sleep_time => 200, 317: name => have_node_in_mnesia 318: }). 319: 320: all_log_levels() -> 321: [<<"NONE">>, 322: <<"EMERGENCY">>, 323: <<"ALERT">>, 324: <<"CRITICAL">>, 325: <<"ERROR">>, 326: <<"WARNING">>, 327: <<"NOTICE">>, 328: <<"INFO">>, 329: <<"DEBUG">>, 330: <<"ALL">>]. 331: 332: have_node_in_mnesia(Node1, #{node := Node2}, ShouldBe) -> 333: DbNodes1 = distributed_helper:rpc(Node1, mnesia, system_info, [db_nodes]), 334: ?assertEqual(ShouldBe, lists:member(Node2, DbNodes1)). 335: 336: get_cookie(Config) -> 337: execute_command(<<"server">>, <<"getCookie">>, #{}, Config). 338: 339: get_loglevel(Config) -> 340: execute_command(<<"server">>, <<"getLoglevel">>, #{}, Config). 341: 342: set_loglevel(LogLevel, Config) -> 343: execute_command(<<"server">>, <<"setLoglevel">>, #{<<"level">> => LogLevel}, Config). 344: 345: get_status(Config) -> 346: execute_command(<<"server">>, <<"status">>, #{}, Config). 347: 348: get_status(Node, Config) -> 349: execute_command(Node, <<"server">>, <<"status">>, #{}, Config). 350: 351: join_cluster(Node, Config) -> 352: execute_command(<<"server">>, <<"joinCluster">>, #{<<"node">> => Node}, Config). 353: 354: leave_cluster(Config) -> 355: execute_command(<<"server">>, <<"leaveCluster">>, #{}, Config). 356: 357: remove_from_cluster(Node, Config) -> 358: execute_command(<<"server">>, <<"removeFromCluster">>, #{<<"node">> => Node}, Config). 359: 360: stop_node(Node, Config) -> 361: execute_command(Node, <<"server">>, <<"stop">>, #{}, Config). 362: 363: remove_node(Node, Config) -> 364: execute_command(Node, <<"server">>, <<"removeNode">>, #{<<"node">> => Node}, Config).