1: -module(graphql_cets_SUITE). 2: -include_lib("eunit/include/eunit.hrl"). 3: 4: -compile([export_all, nowarn_export_all]). 5: 6: -import(distributed_helper, [mim/0, mim2/0, rpc/4]). 7: -import(domain_helper, [host_type/1]). 8: -import(mongooseimctl_helper, [rpc_call/3]). 9: -import(graphql_helper, [execute_command/4, get_unauthorized/1, get_ok_value/2, get_not_loaded/1]). 10: 11: all() -> 12: [{group, admin_cets_cli}, 13: {group, admin_cets_http}, 14: {group, domain_admin_cets}, 15: {group, cets_not_configured}]. 16: 17: groups() -> 18: [{admin_cets_http, [parallel], admin_cets_tests()}, 19: {admin_cets_cli, [parallel], admin_cets_tests()}, 20: {domain_admin_cets, [], domain_admin_tests()}, 21: {cets_not_configured, [parallel], cets_not_configured_test()}]. 22: 23: admin_cets_tests() -> 24: [has_sm_table_in_info, 25: available_nodes, 26: unavailable_nodes, 27: joined_nodes, 28: discovered_nodes, 29: remote_nodes_without_disco, 30: remote_nodes_with_unknown_tables, 31: remote_unknown_tables, 32: remote_nodes_with_missing_tables, 33: remote_missing_tables, 34: conflict_nodes, 35: conflict_tables, 36: discovery_works]. 37: 38: domain_admin_tests() -> 39: [domain_admin_get_table_info_test, 40: domain_admin_get_system_info_test]. 41: 42: cets_not_configured_test() -> 43: [get_table_info_not_configured_test, 44: get_system_info_not_configured_test]. 45: 46: init_per_suite(Config) -> 47: case rpc_call(mongoose_config, get_opt, [[internal_databases, cets, backend], undefined]) of 48: rdbms -> 49: Config1 = escalus:init_per_suite(Config), 50: Config2 = ejabberd_node_utils:init(mim(), Config1), 51: add_bad_node(), 52: ok = rpc_call(cets_discovery, wait_for_ready, [mongoose_cets_discovery, 5000]), 53: Config2 ++ distributed_helper:require_rpc_nodes([mim, mim2]); 54: _ -> 55: Config 56: end. 57: 58: end_per_suite(Config) -> 59: case rpc_call(mongoose_config, lookup_opt, [[internal_databases, cets, backend]]) of 60: {ok, rdbms} -> 61: ensure_bad_node_unregistered(), 62: escalus:end_per_suite(Config); 63: _ -> 64: ok 65: end. 66: 67: init_per_group(admin_cets_http, Config) -> 68: Config1 = graphql_helper:init_admin_handler(Config), 69: skip_if_cets_not_configured(Config1); 70: init_per_group(admin_cets_cli, Config) -> 71: Config1 = graphql_helper:init_admin_cli(Config), 72: skip_if_cets_not_configured(Config1); 73: init_per_group(domain_admin_cets, Config) -> 74: Config1 = graphql_helper:init_domain_admin_handler(Config), 75: skip_if_cets_not_configured(Config1); 76: init_per_group(cets_not_configured, Config) -> 77: case rpc_call(mongoose_config, lookup_opt, [[internal_databases, cets]]) of 78: {error, not_found} -> 79: graphql_helper:init_admin_handler(Config); 80: {ok, _} -> 81: {skip, "CETS is configured"} 82: end. 83: 84: end_per_group(cets_not_configured, _Config) -> 85: graphql_helper:clean(); 86: end_per_group(_, _Config) -> 87: graphql_helper:clean(), 88: escalus_fresh:clean(). 89: 90: skip_if_cets_not_configured(Config) -> 91: case rpc_call(mongoose_config, lookup_opt, [[internal_databases, cets, backend]]) of 92: {ok, rdbms} -> 93: Config; 94: _ -> 95: {skip, "CETS is not configured with RDBMS"} 96: end. 97: 98: init_per_testcase(has_sm_table_in_info, Config) -> 99: case rpc_call(ejabberd_sm, sm_backend, []) of 100: ejabberd_sm_cets -> 101: Config; 102: _ -> 103: {skip, "SM backend is not CETS"} 104: end; 105: init_per_testcase(_, Config) -> 106: Config. 107: 108: % Admin tests 109: 110: has_sm_table_in_info(Config) -> 111: Res = get_table_info(Config), 112: Tables = get_ok_value([data, cets, tableInfo], Res), 113: [T] = [T || T = #{<<"tableName">> := <<"cets_session">>} <- Tables], 114: #{<<"memory">> := Mem, <<"nodes">> := Nodes, <<"size">> := Size} = T, 115: ?assert(is_integer(Mem), T), 116: ?assert(is_integer(Size), T), 117: #{node := Node1} = mim(), 118: assert_member(atom_to_binary(Node1), Nodes). 119: 120: available_nodes(Config) -> 121: #{node := Node1} = mim(), 122: #{node := Node2} = mim2(), 123: Res = get_system_info(Config), 124: Info = get_ok_value([data, cets, systemInfo], Res), 125: #{<<"availableNodes">> := Nodes} = Info, 126: assert_member(atom_to_binary(Node1), Nodes), 127: assert_member(atom_to_binary(Node2), Nodes), 128: assert_not_member(<<"badnode@localhost">>, Nodes). 129: 130: unavailable_nodes(Config) -> 131: #{node := Node1} = mim(), 132: #{node := Node2} = mim2(), 133: Res = get_system_info(Config), 134: Info = get_ok_value([data, cets, systemInfo], Res), 135: #{<<"unavailableNodes">> := Nodes} = Info, 136: assert_member(<<"badnode@localhost">>, Nodes), 137: assert_not_member(atom_to_binary(Node1), Nodes), 138: assert_not_member(atom_to_binary(Node2), Nodes). 139: 140: joined_nodes(Config) -> 141: #{node := Node1} = mim(), 142: #{node := Node2} = mim2(), 143: Res = get_system_info(Config), 144: Info = get_ok_value([data, cets, systemInfo], Res), 145: #{<<"joinedNodes">> := Nodes} = Info, 146: assert_member(atom_to_binary(Node1), Nodes), 147: assert_member(atom_to_binary(Node2), Nodes), 148: assert_not_member(<<"badnode@localhost">>, Nodes). 149: 150: remote_nodes_without_disco(Config) -> 151: Res = get_system_info(Config), 152: Info = get_ok_value([data, cets, systemInfo], Res), 153: ?assert(is_list(maps:get(<<"remoteNodesWithoutDisco">>, Info)), Info). 154: 155: remote_nodes_with_unknown_tables(Config) -> 156: Res = get_system_info(Config), 157: Info = get_ok_value([data, cets, systemInfo], Res), 158: ?assert(is_list(maps:get(<<"remoteNodesWithUnknownTables">>, Info)), Info). 159: 160: remote_unknown_tables(Config) -> 161: Res = get_system_info(Config), 162: Info = get_ok_value([data, cets, systemInfo], Res), 163: ?assert(is_list(maps:get(<<"remoteUnknownTables">>, Info)), Info). 164: 165: remote_nodes_with_missing_tables(Config) -> 166: Res = get_system_info(Config), 167: Info = get_ok_value([data, cets, systemInfo], Res), 168: ?assert(is_list(maps:get(<<"remoteNodesWithMissingTables">>, Info)), Info). 169: 170: remote_missing_tables(Config) -> 171: Res = get_system_info(Config), 172: Info = get_ok_value([data, cets, systemInfo], Res), 173: ?assert(is_list(maps:get(<<"remoteMissingTables">>, Info)), Info). 174: 175: conflict_nodes(Config) -> 176: Res = get_system_info(Config), 177: Info = get_ok_value([data, cets, systemInfo], Res), 178: ?assertMatch(#{<<"conflictNodes">> := []}, Info). 179: 180: conflict_tables(Config) -> 181: Res = get_system_info(Config), 182: Info = get_ok_value([data, cets, systemInfo], Res), 183: ?assertMatch(#{<<"conflictTables">> := []}, Info). 184: 185: conflict_nodes_count(Config) -> 186: Res = get_system_info(Config), 187: Info = get_ok_value([data, cets, systemInfo], Res), 188: ?assertMatch(#{<<"conflictNodesCount">> := 0}, Info). 189: 190: discovered_nodes(Config) -> 191: #{node := Node1} = mim(), 192: #{node := Node2} = mim2(), 193: Res = get_system_info(Config), 194: Info = get_ok_value([data, cets, systemInfo], Res), 195: #{<<"discoveredNodes">> := Nodes} = Info, 196: assert_member(atom_to_binary(Node1), Nodes), 197: assert_member(atom_to_binary(Node2), Nodes), 198: assert_member(<<"badnode@localhost">>, Nodes). 199: 200: discovered_nodes_count(Config) -> 201: Res = get_system_info(Config), 202: Info = get_ok_value([data, cets, systemInfo], Res), 203: #{<<"discoveredNodesCount">> := Count} = Info, 204: ?assert(is_integer(Count), Info), 205: ?assert(Count > 2, Info). 206: 207: discovery_works(Config) -> 208: Res = get_system_info(Config), 209: Info = get_ok_value([data, cets, systemInfo], Res), 210: ?assertMatch(#{<<"discoveryWorks">> := true}, Info). 211: 212: % Domain admin tests 213: 214: domain_admin_get_table_info_test(Config) -> 215: get_unauthorized(get_table_info(Config)). 216: 217: domain_admin_get_system_info_test(Config) -> 218: get_unauthorized(get_system_info(Config)). 219: 220: % CETS not configured tests 221: 222: get_table_info_not_configured_test(Config) -> 223: get_not_loaded(get_table_info(Config)). 224: 225: get_system_info_not_configured_test(Config) -> 226: get_not_loaded(get_system_info(Config)). 227: 228: %-------------------------------------------------------------------------------------------------- 229: % Helpers 230: %-------------------------------------------------------------------------------------------------- 231: 232: get_table_info(Config) -> 233: execute_command(<<"cets">>, <<"tableInfo">>, #{}, Config). 234: 235: get_system_info(Config) -> 236: execute_command(<<"cets">>, <<"systemInfo">>, #{}, Config). 237: 238: add_bad_node() -> 239: ensure_bad_node_unregistered(), 240: register_bad_node(), 241: force_check(), 242: wait_for_has_bad_node(). 243: 244: register_bad_node() -> 245: ClusterName = <<"mim">>, 246: Node = <<"badnode@localhost">>, 247: Num = 100, 248: Address = <<>>, 249: Timestamp = rpc(mim(), mongoose_rdbms_timestamp, select, []), 250: InsertArgs = [ClusterName, Node, Num, Address, Timestamp], 251: {updated, 1} = rpc(mim(), mongoose_cets_discovery_rdbms, insert_new, InsertArgs). 252: 253: ensure_bad_node_unregistered() -> 254: ClusterName = <<"mim">>, 255: Node = <<"badnode@localhost">>, 256: DeleteArgs = [ClusterName, Node], 257: %% Ensure the node is removed 258: {updated, _} = rpc(mim(), mongoose_cets_discovery_rdbms, delete_node_from_db, DeleteArgs). 259: 260: force_check() -> 261: Pid = rpc(mim(), erlang, whereis, [mongoose_cets_discovery]), 262: true = is_pid(Pid), 263: Pid ! check. 264: 265: has_bad_node() -> 266: #{unavailable_nodes := UnNodes} = 267: rpc(mim(), cets_discovery, system_info, [mongoose_cets_discovery]), 268: lists:member('badnode@localhost', UnNodes). 269: 270: wait_for_has_bad_node() -> 271: mongoose_helper:wait_until(fun() -> has_bad_node() end, true). 272: 273: assert_member(Elem, List) -> 274: lists:member(Elem, List) 275: orelse ct:fail({assert_member_failed, Elem, List}). 276: 277: assert_not_member(Elem, List) -> 278: lists:member(Elem, List) 279: andalso ct:fail({assert_member_failed, Elem, List}).