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: 148: 149: join_successful(Config) -> 150: #{node := Node2} = RPCSpec2 = mim2(), 151: leave_cluster(Config), 152: get_ok_value([], join_cluster(atom_to_binary(Node2), Config)), 153: distributed_helper:verify_result(RPCSpec2, add). 154: 155: leave_successful(Config) -> 156: #{node := Node2} = RPCSpec2 = mim2(), 157: join_cluster(atom_to_binary(Node2), Config), 158: get_ok_value([], leave_cluster(Config)), 159: distributed_helper:verify_result(RPCSpec2, remove). 160: 161: join_unsuccessful(Config) -> 162: Node2 = mim2(), 163: join_cluster(<<>>, Config), 164: distributed_helper:verify_result(Node2, remove). 165: 166: leave_but_no_cluster(Config) -> 167: Node2 = mim2(), 168: get_err_code(leave_cluster(Config)), 169: distributed_helper:verify_result(Node2, remove). 170: 171: join_twice(Config) -> 172: #{node := Node2} = RPCSpec2 = mim2(), 173: get_ok_value([], join_cluster(atom_to_binary(Node2), Config)), 174: ?assertEqual(<<"already_joined">>, get_err_code(join_cluster(atom_to_binary(Node2), Config))), 175: distributed_helper:verify_result(RPCSpec2, add). 176: 177: leave_twice(Config) -> 178: #{node := Node2} = RPCSpec2 = mim2(), 179: join_cluster(atom_to_binary(Node2), Config), 180: get_ok_value([], leave_cluster(Config)), 181: distributed_helper:verify_result(RPCSpec2, remove), 182: ?assertEqual(<<"not_in_cluster">>, get_err_code(leave_cluster(Config))). 183: 184: remove_dead_from_cluster(Config) -> 185: % given 186: Timeout = timer:seconds(60), 187: #{node := Node1Nodename} = Node1 = mim(), 188: #{node := _Node2Nodename} = Node2 = mim2(), 189: #{node := Node3Nodename} = Node3 = mim3(), 190: ok = rpc(Node2#{timeout => Timeout}, mongoose_cluster, join, [Node1Nodename]), 191: ok = rpc(Node3#{timeout => Timeout}, mongoose_cluster, join, [Node1Nodename]), 192: %% when 193: distributed_helper:stop_node(Node3Nodename, Config), 194: get_ok_value([data, server, removeFromCluster], 195: remove_from_cluster(atom_to_binary(Node3Nodename), Config)), 196: %% then 197: % node is down hence its not in mnesia cluster 198: have_node_in_mnesia_wait(Node1, Node2, true), 199: have_node_in_mnesia_wait(Node1, Node3, false), 200: have_node_in_mnesia_wait(Node2, Node3, false), 201: % after node awakening nodes are clustered again 202: distributed_helper:start_node(Node3Nodename, Config), 203: have_node_in_mnesia_wait(Node1, Node3, true), 204: have_node_in_mnesia_wait(Node2, Node3, true). 205: 206: remove_alive_from_cluster(Config) -> 207: % given 208: Timeout = timer:seconds(60), 209: #{node := Node1Name} = Node1 = mim(), 210: #{node := Node2Name} = Node2 = mim2(), 211: Node3 = mim3(), 212: ok = rpc(Node2#{timeout => Timeout}, mongoose_cluster, join, [Node1Name]), 213: ok = rpc(Node3#{timeout => Timeout}, mongoose_cluster, join, [Node1Name]), 214: %% when 215: %% Node2 is still running 216: %% then 217: get_ok_value([], remove_from_cluster(atom_to_binary(Node2Name), Config)), 218: have_node_in_mnesia(Node1, Node3, true), 219: have_node_in_mnesia(Node1, Node2, false), 220: have_node_in_mnesia(Node3, Node2, false). 221: 222: remove_node_test(Config) -> 223: #{node := NodeName} = mim3(), 224: Value = get_ok_value([data, server, removeNode], remove_node(NodeName, Config)), 225: ?assertEqual(<<"MongooseIM node removed from the Mnesia schema">>, Value). 226: 227: stop_node_test(Config) -> 228: #{node := Node3Nodename} = mim3(), 229: get_ok_value([data, server, stop], stop_node(Node3Nodename, Config)), 230: Timeout = timer:seconds(3), 231: F = fun() -> rpc:call(Node3Nodename, application, which_applications, [], Timeout) end, 232: mongoose_helper:wait_until(F, {badrpc, nodedown}, #{sleep_time => 1000, name => stop_node}), 233: distributed_helper:start_node(Node3Nodename, Config). 234: 235: join_successful_http(Config) -> 236: #{node := Node2} = RPCSpec2 = mim2(), 237: leave_cluster(Config), 238: distributed_helper:verify_result(RPCSpec2, remove), 239: get_ok_value([], join_cluster(atom_to_binary(Node2), Config)), 240: distributed_helper:verify_result(RPCSpec2, add). 241: 242: leave_successful_http(Config) -> 243: #{node := Node2} = RPCSpec2 = mim2(), 244: join_cluster(atom_to_binary(Node2), Config), 245: distributed_helper:verify_result(RPCSpec2, add), 246: get_ok_value([], leave_cluster(Config)), 247: distributed_helper:verify_result(RPCSpec2, remove). 248: 249: remove_dead_from_cluster_http(Config) -> 250: % given 251: Timeout = timer:seconds(60), 252: #{node := Node1Nodename} = Node1 = mim(), 253: #{node := _Node2Nodename} = Node2 = mim2(), 254: #{node := Node3Nodename} = Node3 = mim3(), 255: ok = rpc(Node2#{timeout => Timeout}, mongoose_cluster, join, [Node1Nodename]), 256: ok = rpc(Node3#{timeout => Timeout}, mongoose_cluster, join, [Node1Nodename]), 257: %% when 258: distributed_helper:stop_node(Node3Nodename, Config), 259: F2 = fun() -> 260: test == rpc(Node1#{timeout => Timeout}, mongoose_config, get_opt, [listen, test]) 261: end, 262: mongoose_helper:wait_until(F2, false, #{sleep_time => 200, name => wait_for_mim1, 263: time_left => timer:seconds(20)}), 264: get_ok_value([data, server, removeFromCluster], 265: remove_from_cluster(atom_to_binary(Node3Nodename), Config)), 266: have_node_in_mnesia_wait(Node1, Node2, true), 267: have_node_in_mnesia_wait(Node1, Node3, false), 268: have_node_in_mnesia_wait(Node2, Node3, false), 269: % after node awakening nodes are clustered again 270: distributed_helper:start_node(Node3Nodename, Config), 271: ensure_node_started(Node3), 272: have_node_in_mnesia_wait(Node1, Node3, true), 273: have_node_in_mnesia_wait(Node2, Node3, true). 274: 275: remove_alive_from_cluster_http(Config) -> 276: % given 277: Timeout = timer:seconds(60), 278: #{node := Node1Name} = Node1 = mim(), 279: #{node := Node2Name} = Node2 = mim2(), 280: Node3 = mim3(), 281: ok = rpc(Node2#{timeout => Timeout}, mongoose_cluster, join, [Node1Name]), 282: ok = rpc(Node3#{timeout => Timeout}, mongoose_cluster, join, [Node1Name]), 283: %% when 284: %% Node2 is still running 285: %% then 286: get_ok_value([], remove_from_cluster(atom_to_binary(Node2Name), Config)), 287: have_node_in_mnesia_wait(Node1, Node3, true), 288: have_node_in_mnesia_wait(Node1, Node2, false), 289: have_node_in_mnesia_wait(Node3, Node2, false). 290: 291: ensure_node_started(Node) -> 292: Timeout = timer:seconds(60), 293: F = fun() -> 294: case rpc(Node#{timeout => Timeout}, mongoose_server_api, status, []) of 295: {ok, {true, _, _}} -> true; 296: _Other -> false 297: end 298: end, 299: mongoose_helper:wait_until(F, true, #{sleep_time => 200, name => wait_for_start_mim3, 300: time_left => timer:seconds(20)}). 301: 302: %----------------------------------------------------------------------- 303: % Helpers 304: %----------------------------------------------------------------------- 305: 306: have_node_in_mnesia_wait(Node1, #{node := Node2}, Value) -> 307: mongoose_helper:wait_until(fun() -> 308: DbNodes1 = distributed_helper:rpc(Node1, mnesia, 309: system_info, [db_nodes]), 310: lists:member(Node2, DbNodes1) 311: end, 312: Value, 313: #{ 314: time_left => timer:seconds(12), 315: sleep_time => 200, 316: name => have_node_in_mnesia 317: }). 318: 319: all_log_levels() -> 320: [<<"NONE">>, 321: <<"EMERGENCY">>, 322: <<"ALERT">>, 323: <<"CRITICAL">>, 324: <<"ERROR">>, 325: <<"WARNING">>, 326: <<"NOTICE">>, 327: <<"INFO">>, 328: <<"DEBUG">>, 329: <<"ALL">>]. 330: 331: have_node_in_mnesia(Node1, #{node := Node2}, ShouldBe) -> 332: DbNodes1 = distributed_helper:rpc(Node1, mnesia, system_info, [db_nodes]), 333: ?assertEqual(ShouldBe, lists:member(Node2, DbNodes1)). 334: 335: get_cookie(Config) -> 336: execute_command(<<"server">>, <<"getCookie">>, #{}, Config). 337: 338: get_loglevel(Config) -> 339: execute_command(<<"server">>, <<"getLoglevel">>, #{}, Config). 340: 341: set_loglevel(LogLevel, Config) -> 342: execute_command(<<"server">>, <<"setLoglevel">>, #{<<"level">> => LogLevel}, Config). 343: 344: get_status(Config) -> 345: execute_command(<<"server">>, <<"status">>, #{}, Config). 346: 347: get_status(Node, Config) -> 348: execute_command(Node, <<"server">>, <<"status">>, #{}, Config). 349: 350: join_cluster(Node, Config) -> 351: execute_command(<<"server">>, <<"joinCluster">>, #{<<"node">> => Node}, Config). 352: 353: leave_cluster(Config) -> 354: execute_command(<<"server">>, <<"leaveCluster">>, #{}, Config). 355: 356: remove_from_cluster(Node, Config) -> 357: execute_command(<<"server">>, <<"removeFromCluster">>, #{<<"node">> => Node}, Config). 358: 359: stop_node(Node, Config) -> 360: execute_command(Node, <<"server">>, <<"stop">>, #{}, Config). 361: 362: remove_node(Node, Config) -> 363: execute_command(Node, <<"server">>, <<"removeNode">>, #{<<"node">> => Node}, Config).