1: -module(graphql_metric_SUITE). 2: 3: -include_lib("eunit/include/eunit.hrl"). 4: 5: -compile([export_all, nowarn_export_all]). 6: 7: -import(distributed_helper, [mim/0, require_rpc_nodes/1, rpc/4]). 8: -import(graphql_helper, [execute_command/4, get_ok_value/2, get_unauthorized/1, 9: get_err_msg/1, get_err_code/1]). 10: 11: suite() -> 12: MIM2NodeName = maps:get(node, distributed_helper:mim2()), 13: %% Ensure nodes are connected 14: mongoose_helper:successful_rpc(net_kernel, connect_node, [MIM2NodeName]), 15: require_rpc_nodes([mim, mim2]) ++ escalus:suite(). 16: 17: all() -> 18: [{group, metrics_http}, 19: {group, metrics_cli}, 20: {group, domain_admin_metrics}]. 21: 22: groups() -> 23: [{metrics_http, [], metrics_tests()}, 24: {metrics_cli, [], metrics_tests()}, 25: {domain_admin_metrics, [], domain_admin_metrics_tests()}]. 26: 27: metrics_tests() -> 28: [get_all_metrics, 29: get_all_metrics_check_by_type, 30: get_by_name_global_erlang_metrics, 31: get_metrics_by_name_empty_args, 32: get_metrics_by_name_empty_string, 33: get_metrics_by_nonexistent_name, 34: get_metrics_for_specific_host_type, 35: get_process_queue_length, 36: get_inet_stats, 37: get_vm_stats_memory, 38: get_cets_system, 39: get_all_metrics_as_dicts, 40: get_by_name_metrics_as_dicts, 41: get_metrics_as_dicts_by_nonexistent_name, 42: get_metrics_as_dicts_with_key_one, 43: get_metrics_as_dicts_with_nonexistent_key, 44: get_metrics_as_dicts_empty_args, 45: get_metrics_as_dicts_empty_strings, 46: get_cluster_metrics, 47: get_by_name_cluster_metrics_as_dicts, 48: get_mim2_cluster_metrics, 49: get_cluster_metrics_for_nonexistent_nodes, 50: get_cluster_metrics_by_nonexistent_name, 51: get_cluster_metrics_with_nonexistent_key, 52: get_cluster_metrics_empty_args, 53: get_cluster_metrics_empty_strings]. 54: 55: domain_admin_metrics_tests() -> 56: [domain_admin_get_metrics, 57: domain_admin_get_metrics_as_dicts, 58: domain_admin_get_metrics_as_dicts_by_name, 59: domain_admin_get_metrics_as_dicts_with_keys, 60: domain_admin_get_cluster_metrics_as_dicts, 61: domain_admin_get_cluster_metrics_as_dicts_by_name, 62: domain_admin_get_cluster_metrics_as_dicts_for_nodes]. 63: 64: init_per_suite(Config) -> 65: Config1 = ejabberd_node_utils:init(mim(), Config), 66: escalus:init_per_suite(Config1). 67: 68: end_per_suite(Config) -> 69: escalus_fresh:clean(), 70: escalus:end_per_suite(Config). 71: 72: init_per_group(metrics_http, Config) -> 73: graphql_helper:init_admin_handler(Config); 74: init_per_group(metrics_cli, Config) -> 75: graphql_helper:init_admin_cli(Config); 76: init_per_group(domain_admin_metrics, Config) -> 77: graphql_helper:init_domain_admin_handler(Config). 78: 79: end_per_group(_GroupName, _Config) -> 80: graphql_helper:clean(). 81: 82: init_per_testcase(get_cets_system = CaseName, Config) -> 83: case is_cets_enabled() of 84: true -> 85: escalus:init_per_testcase(CaseName, Config); 86: false -> 87: {skip, cets_not_enabled} 88: end; 89: init_per_testcase(CaseName, Config) -> 90: escalus:init_per_testcase(CaseName, Config). 91: 92: end_per_testcase(CaseName, Config) -> 93: escalus:end_per_testcase(CaseName, Config). 94: 95: get_all_metrics(Config) -> 96: Result = get_metrics(Config), 97: ParsedResult = get_ok_value([data, metric, getMetrics], Result), 98: Map = maps:from_list([{Name, X} || X = #{<<"name">> := Name} <- ParsedResult]), 99: ReadsKey = [<<"global">>, <<"backends">>, <<"mod_roster">>, <<"read_roster_version">>], 100: Reads = maps:get(ReadsKey, Map), 101: %% Histogram integer keys have p prefix 102: check_histogram_p(Reads), 103: %% HistogramMetric type 104: #{<<"type">> := <<"histogram">>} = Reads. 105: 106: get_all_metrics_check_by_type(Config) -> 107: Result = get_metrics(Config), 108: ParsedResult = get_ok_value([data, metric, getMetrics], Result), 109: lists:foreach(fun check_metric_by_type/1, ParsedResult). 110: 111: check_metric_by_type(#{<<"type">> := Type} = Map) -> 112: values_are_integers(Map, type_to_keys(Type)). 113: 114: type_to_keys(<<"histogram">>) -> 115: [<<"n">>, <<"mean">>, <<"min">>, <<"max">>, <<"median">>, 116: <<"p50">>, <<"p75">>, <<"p90">>, <<"p95">>, <<"p99">>, <<"p999">>]; 117: type_to_keys(<<"counter">>) -> 118: [<<"value">>, <<"ms_since_reset">>]; 119: type_to_keys(<<"spiral">>) -> 120: [<<"one">>, <<"count">>]; 121: type_to_keys(<<"gauge">>) -> 122: [<<"value">>]; 123: type_to_keys(<<"merged_inet_stats">>) -> 124: [<<"connections">>, <<"recv_cnt">>, <<"recv_max">>, <<"recv_oct">>, 125: <<"send_cnt">>, <<"send_max">>, <<"send_oct">>, <<"send_pend">>]; 126: type_to_keys(<<"rdbms_stats">>) -> 127: [<<"workers">>, <<"recv_cnt">>, <<"recv_max">>, <<"recv_oct">>, 128: <<"send_cnt">>, <<"send_max">>, <<"send_oct">>, <<"send_pend">>]; 129: type_to_keys(<<"vm_stats_memory">>) -> 130: [<<"atom_used">>, <<"binary">>, <<"ets">>, 131: <<"processes_used">>, <<"system">>, <<"total">>]; 132: type_to_keys(<<"vm_system_info">>) -> 133: [<<"ets_limit">>, <<"port_count">>, <<"port_limit">>, 134: <<"process_count">>, <<"process_limit">>]; 135: type_to_keys(<<"probe_queues">>) -> 136: [<<"fsm">>, <<"regular">>, <<"total">>]; 137: type_to_keys(<<"cets_system">>) -> 138: [<<"available_nodes">>, <<"unavailable_nodes">>, 139: <<"remote_nodes_without_disco">>, <<"joined_nodes">>, 140: <<"remote_nodes_with_unknown_tables">>, <<"remote_unknown_tables">>, 141: <<"remote_nodes_with_missing_tables">>, <<"remote_missing_tables">>, 142: <<"conflict_nodes">>, <<"conflict_tables">>, 143: <<"discovered_nodes">>, <<"discovery_works">>]. 144: 145: get_by_name_global_erlang_metrics(Config) -> 146: %% Filter by name works 147: Result = get_metrics([<<"global">>, <<"erlang">>], Config), 148: ParsedResult = get_ok_value([data, metric, getMetrics], Result), 149: Map = maps:from_list([{Name, X} || X = #{<<"name">> := Name} <- ParsedResult]), 150: Info = maps:get([<<"global">>, <<"erlang">>, <<"system_info">>], Map), 151: %% VMSystemInfoMetric type 152: #{<<"type">> := <<"vm_system_info">>} = Info, 153: check_metric_by_type(Info), 154: ReadsKey = [<<"global">>, <<"backends">>, <<"mod_roster">>, <<"read_roster_version">>], 155: %% Other metrics are filtered out 156: undef = maps:get(ReadsKey, Map, undef). 157: 158: get_metrics_by_name_empty_args(Config) -> 159: Result = get_metrics([], Config), 160: ParsedResult = get_ok_value([data, metric, getMetrics], Result), 161: lists:foreach(fun check_metric_by_type/1, ParsedResult), 162: [_|_] = ParsedResult. 163: 164: get_metrics_by_name_empty_string(Config) -> 165: Result = get_metrics([<<>>], Config), 166: ParsedResult = get_ok_value([data, metric, getMetrics], Result), 167: [] = ParsedResult. 168: 169: get_metrics_by_nonexistent_name(Config) -> 170: Result = get_metrics([<<"not_existing">>], Config), 171: ParsedResult = get_ok_value([data, metric, getMetrics], Result), 172: [] = ParsedResult. 173: 174: get_metrics_for_specific_host_type(Config) -> 175: Result = get_metrics([<<"dummy auth">>], Config), 176: ParsedResult = get_ok_value([data, metric, getMetrics], Result), 177: lists:foreach(fun check_metric_by_type/1, ParsedResult), 178: [_|_] = ParsedResult. 179: 180: get_process_queue_length(Config) -> 181: Result = get_metrics([<<"global">>, <<"processQueueLengths">>], Config), 182: ParsedResult = get_ok_value([data, metric, getMetrics], Result), 183: Map = maps:from_list([{Name, X} || X = #{<<"name">> := Name} <- ParsedResult]), 184: Lens = maps:get([<<"global">>, <<"processQueueLengths">>], Map), 185: %% ProbeQueuesMetric type 186: #{<<"type">> := <<"probe_queues">>} = Lens, 187: check_metric_by_type(Lens). 188: 189: get_inet_stats(Config) -> 190: Result = get_metrics([<<"global">>, <<"data">>, <<"dist">>], Config), 191: ParsedResult = get_ok_value([data, metric, getMetrics], Result), 192: Map = maps:from_list([{Name, X} || X = #{<<"name">> := Name} <- ParsedResult]), 193: Stats = maps:get([<<"global">>, <<"data">>, <<"dist">>], Map), 194: %% MergedInetStatsMetric type 195: #{<<"type">> := <<"merged_inet_stats">>} = Stats, 196: check_metric_by_type(Stats). 197: 198: get_vm_stats_memory(Config) -> 199: Result = get_metrics([<<"global">>], Config), 200: ParsedResult = get_ok_value([data, metric, getMetrics], Result), 201: Map = maps:from_list([{Name, X} || X = #{<<"name">> := Name} <- ParsedResult]), 202: Mem = maps:get([<<"global">>, <<"erlang">>, <<"memory">>], Map), 203: %% VMStatsMemoryMetric type 204: #{<<"type">> := <<"vm_stats_memory">>} = Mem, 205: check_metric_by_type(Mem). 206: 207: get_cets_system(Config) -> 208: Result = get_metrics([<<"global">>, <<"cets">>, <<"system">>], Config), 209: ParsedResult = get_ok_value([data, metric, getMetrics], Result), 210: [#{<<"type">> := <<"cets_system">>} = Sys] = ParsedResult, 211: check_metric_by_type(Sys). 212: 213: get_all_metrics_as_dicts(Config) -> 214: Result = get_metrics_as_dicts(Config), 215: ParsedResult = get_ok_value([data, metric, getMetricsAsDicts], Result), 216: check_node_result_is_valid(ParsedResult, false). 217: 218: get_by_name_metrics_as_dicts(Config) -> 219: Result = get_metrics_as_dicts_by_name([<<"_">>, <<"xmppStanzaSent">>], Config), 220: ParsedResult = get_ok_value([data, metric, getMetricsAsDicts], Result), 221: [_|_] = ParsedResult, 222: %% Only xmppStanzaSent type 223: lists:foreach(fun(#{<<"dict">> := Dict, <<"name">> := [_, <<"xmppStanzaSent">>]}) -> 224: check_spiral_dict(Dict) 225: end, ParsedResult). 226: 227: get_metrics_as_dicts_by_nonexistent_name(Config) -> 228: Result = get_metrics_as_dicts_by_name([<<"not_existing">>], Config), 229: ParsedResult = get_ok_value([data, metric, getMetricsAsDicts], Result), 230: [] = ParsedResult. 231: 232: get_metrics_as_dicts_with_key_one(Config) -> 233: Result = get_metrics_as_dicts_with_keys([<<"one">>], Config), 234: ParsedResult = get_ok_value([data, metric, getMetricsAsDicts], Result), 235: Map = dict_objects_to_map(ParsedResult), 236: SentName = [metric_host_type(), <<"xmppStanzaSent">>], 237: [#{<<"key">> := <<"one">>, <<"value">> := One}] = maps:get(SentName, Map), 238: ?assert(is_integer(One)). 239: 240: get_metrics_as_dicts_with_nonexistent_key(Config) -> 241: Result = get_metrics_as_dicts_with_keys([<<"not_existing">>], Config), 242: ParsedResult = get_ok_value([data, metric, getMetricsAsDicts], Result), 243: Map = dict_objects_to_map(ParsedResult), 244: SentName = [<<"global">>, <<"data">>, <<"xmpp">>, <<"received">>, <<"xml_stanza_size">>], 245: [] = maps:get(SentName, Map). 246: 247: get_metrics_as_dicts_empty_args(Config) -> 248: %% Empty name 249: Result = get_metrics_as_dicts([], [<<"median">>], Config), 250: ParsedResult = get_ok_value([data, metric, getMetricsAsDicts], Result), 251: Map = dict_objects_to_map(ParsedResult), 252: SentName = [<<"global">>, <<"data">>, <<"xmpp">>, <<"received">>, <<"xml_stanza_size">>], 253: [#{<<"key">> := <<"median">>, <<"value">> := Median}] = maps:get(SentName, Map), 254: ?assert(is_integer(Median)), 255: %% Empty keys 256: Result2 = get_metrics_as_dicts([<<"global">>, <<"erlang">>], [], Config), 257: ParsedResult2 = get_ok_value([data, metric, getMetricsAsDicts], Result2), 258: ?assertEqual(length(ParsedResult2), 2). 259: 260: get_metrics_as_dicts_empty_strings(Config) -> 261: %% Name is an empty string 262: Result = get_metrics_as_dicts([<<>>], [<<"median">>], Config), 263: ParsedResult = get_ok_value([data, metric, getMetricsAsDicts], Result), 264: [] = ParsedResult, 265: %% Key is an empty string 266: Result2 = get_metrics_as_dicts([<<"global">>, <<"erlang">>], [<<>>], Config), 267: ParsedResult2 = get_ok_value([data, metric, getMetricsAsDicts], Result2), 268: [_|_] = ParsedResult2. 269: 270: get_cluster_metrics(Config) -> 271: %% We will have at least these two nodes 272: Node1 = atom_to_binary(maps:get(node, distributed_helper:mim())), 273: Node2 = atom_to_binary(maps:get(node, distributed_helper:mim2())), 274: Result = get_cluster_metrics_as_dicts(Config), 275: ParsedResult = get_ok_value([data, metric, getClusterMetricsAsDicts], Result), 276: #{Node1 := Res1, Node2 := Res2} = node_objects_to_map(ParsedResult), 277: check_node_result_is_valid(Res1, false), 278: check_node_result_is_valid(Res2, true). 279: 280: get_by_name_cluster_metrics_as_dicts(Config) -> 281: Result = get_cluster_metrics_as_dicts_by_name([<<"_">>, <<"xmppStanzaSent">>], Config), 282: NodeResult = get_ok_value([data, metric, getClusterMetricsAsDicts], Result), 283: Map = node_objects_to_map(NodeResult), 284: %% Contains data for at least two nodes 285: ?assert(maps:size(Map) > 1), 286: %% Only xmppStanzaSent type 287: maps:map(fun(_Node, [_|_] = NodeRes) -> 288: lists:foreach(fun(#{<<"dict">> := Dict, 289: <<"name">> := [_, <<"xmppStanzaSent">>]}) -> 290: check_spiral_dict(Dict) 291: end, NodeRes) end, Map). 292: 293: get_mim2_cluster_metrics(Config) -> 294: Node = atom_to_binary(maps:get(node, distributed_helper:mim2())), 295: Result = get_cluster_metrics_as_dicts_for_nodes([Node], Config), 296: ParsedResult = get_ok_value([data, metric, getClusterMetricsAsDicts], Result), 297: [#{<<"node">> := Node, <<"result">> := ResList}] = ParsedResult, 298: check_node_result_is_valid(ResList, true). 299: 300: get_cluster_metrics_for_nonexistent_nodes(Config) -> 301: Result = get_cluster_metrics_as_dicts_for_nodes([<<"nonexistent">>], Config), 302: ParsedResult = get_ok_value([data, metric, getClusterMetricsAsDicts], Result), 303: [#{<<"node">> := _, <<"result">> := ResList}] = ParsedResult, 304: [#{<<"dict">> := [], <<"name">> := ErrorResult}] = ResList, 305: ?assert(ErrorResult == [<<"error">>, <<"nodedown">>]). 306: 307: get_cluster_metrics_by_nonexistent_name(Config) -> 308: Result = get_cluster_metrics_as_dicts_by_name([<<"nonexistent">>], Config), 309: ParsedResult = get_ok_value([data, metric, getClusterMetricsAsDicts], Result), 310: [#{<<"node">> := _, <<"result">> := []}, 311: #{<<"node">> := _, <<"result">> := []}|_] = ParsedResult. %% two or three nodes. 312: 313: get_cluster_metrics_with_nonexistent_key(Config) -> 314: Result = get_cluster_metrics_as_dicts_with_keys([<<"nonexistent">>], Config), 315: ParsedResult = get_ok_value([data, metric, getClusterMetricsAsDicts], Result), 316: [#{<<"node">> := _, <<"result">> := [_|_]}, 317: #{<<"node">> := _, <<"result">> := [_|_]}|_] = ParsedResult. 318: 319: get_cluster_metrics_empty_args(Config) -> 320: Node = atom_to_binary(maps:get(node, distributed_helper:mim2())), 321: %% Empty name 322: Result = get_cluster_metrics_as_dicts([], [<<"one">>], [Node], Config), 323: ParsedResult = get_ok_value([data, metric, getClusterMetricsAsDicts], Result), 324: [#{<<"node">> := Node, <<"result">> := ResList}] = ParsedResult, 325: Map = dict_objects_to_map(ResList), 326: SentName = [<<"global">>, <<"xmppStanzaSent">>], 327: [#{<<"key">> := <<"one">>, <<"value">> := One}] = maps:get(SentName, Map), 328: ?assert(is_integer(One)), 329: %% Empty keys 330: Result2 = get_cluster_metrics_as_dicts([<<"_">>], [], [Node], Config), 331: ParsedResult2 = get_ok_value([data, metric, getClusterMetricsAsDicts], Result2), 332: [#{<<"node">> := Node, <<"result">> := ResList2}] = ParsedResult2, 333: check_node_result_is_valid(ResList2, true), 334: %% Empty nodes 335: Result3 = get_cluster_metrics_as_dicts([<<"_">>, <<"erlang">>], [<<"ets_limit">>], [], Config), 336: ParsedResult3 = get_ok_value([data, metric, getClusterMetricsAsDicts], Result3), 337: NodeMap = node_objects_to_map(ParsedResult3), 338: ?assert(maps:size(NodeMap) > 1). 339: 340: get_cluster_metrics_empty_strings(Config) -> 341: Node = atom_to_binary(maps:get(node, distributed_helper:mim2())), 342: %% Name is an empty string 343: Result = get_cluster_metrics_as_dicts([<<>>], [<<"median">>], [Node], Config), 344: ParsedResult = get_ok_value([data, metric, getClusterMetricsAsDicts], Result), 345: [#{<<"node">> := Node, <<"result">> := []}] = ParsedResult, 346: %% Key is an empty string 347: Result2 = get_cluster_metrics_as_dicts([<<"_">>], [<<>>], [Node], Config), 348: ParsedResult2 = get_ok_value([data, metric, getClusterMetricsAsDicts], Result2), 349: [#{<<"node">> := Node, <<"result">> := [_|_]}] = ParsedResult2, 350: %% Node is an empty string 351: Result3 = get_cluster_metrics_as_dicts([<<"_">>], [<<"median">>], [<<>>], Config), 352: ParsedResult3 = get_ok_value([data, metric, getClusterMetricsAsDicts], Result3), 353: [#{<<"node">> := _, <<"result">> := ResList}] = ParsedResult3, 354: [#{<<"dict">> := [], <<"name">> := ErrorResult}] = ResList, 355: ?assert(ErrorResult == [<<"error">>, <<"nodedown">>]). 356: 357: check_node_result_is_valid(ResList, MetricsAreGlobal) -> 358: %% Check that result contains something 359: Map = dict_objects_to_map(ResList), 360: SentName = case MetricsAreGlobal of 361: true -> [<<"global">>, <<"xmppStanzaSent">>]; 362: false -> [metric_host_type(), <<"xmppStanzaSent">>] 363: end, 364: check_spiral_dict(maps:get(SentName, Map)), 365: [#{<<"key">> := <<"value">>,<<"value">> := V}] = 366: maps:get([<<"global">>,<<"uniqueSessionCount">>], Map), 367: ?assert(is_integer(V)), 368: HistObjects = maps:get([<<"global">>, <<"data">>, <<"xmpp">>, 369: <<"sent">>, <<"xml_stanza_size">>], Map), 370: check_histogram(kv_objects_to_map(HistObjects)). 371: 372: check_histogram(Map) -> 373: Keys = [<<"n">>, <<"mean">>, <<"min">>, <<"max">>, <<"median">>, 374: <<"50">>, <<"75">>, <<"90">>, <<"95">>, <<"99">>, <<"999">>], 375: values_are_integers(Map, Keys). 376: 377: check_histogram_p(Map) -> 378: Keys = type_to_keys(<<"histogram">>), 379: values_are_integers(Map, Keys). 380: 381: dict_objects_to_map(List) -> 382: KV = [{Name, Dict} || #{<<"name">> := Name, <<"dict">> := Dict} <- List], 383: maps:from_list(KV). 384: 385: node_objects_to_map(List) -> 386: KV = [{Name, Value} || #{<<"node">> := Name, <<"result">> := Value} <- List], 387: maps:from_list(KV). 388: 389: kv_objects_to_map(List) -> 390: KV = [{Key, Value} || #{<<"key">> := Key, <<"value">> := Value} <- List], 391: maps:from_list(KV). 392: 393: %% Domain admin test cases 394: 395: domain_admin_get_metrics(Config) -> 396: get_unauthorized(get_metrics(Config)). 397: 398: domain_admin_get_metrics_as_dicts(Config) -> 399: get_unauthorized(get_metrics_as_dicts(Config)). 400: 401: domain_admin_get_metrics_as_dicts_by_name(Config) -> 402: get_unauthorized(get_metrics_as_dicts_by_name([<<"_">>], Config)). 403: 404: domain_admin_get_metrics_as_dicts_with_keys(Config) -> 405: get_unauthorized(get_metrics_as_dicts_with_keys([<<"one">>], Config)). 406: 407: domain_admin_get_cluster_metrics_as_dicts(Config) -> 408: get_unauthorized(get_cluster_metrics_as_dicts(Config)). 409: 410: domain_admin_get_cluster_metrics_as_dicts_by_name(Config) -> 411: get_unauthorized(get_cluster_metrics_as_dicts_by_name([<<"_">>], Config)). 412: 413: domain_admin_get_cluster_metrics_as_dicts_for_nodes(Config) -> 414: Node = atom_to_binary(maps:get(node, distributed_helper:mim2())), 415: get_unauthorized(get_cluster_metrics_as_dicts_for_nodes([Node], Config)). 416: 417: %% Admin commands 418: 419: get_metrics(Config) -> 420: execute_command(<<"metric">>, <<"getMetrics">>, #{}, Config). 421: 422: get_metrics(Name, Config) -> 423: Vars = #{<<"name">> => Name}, 424: execute_command(<<"metric">>, <<"getMetrics">>, Vars, Config). 425: 426: get_metrics_as_dicts(Config) -> 427: execute_command(<<"metric">>, <<"getMetricsAsDicts">>, #{}, Config). 428: 429: get_metrics_as_dicts(Name, Keys, Config) -> 430: Vars = #{<<"name">> => Name, <<"keys">> => Keys}, 431: execute_command(<<"metric">>, <<"getMetricsAsDicts">>, Vars, Config). 432: 433: get_metrics_as_dicts_by_name(Name, Config) -> 434: Vars = #{<<"name">> => Name}, 435: execute_command(<<"metric">>, <<"getMetricsAsDicts">>, Vars, Config). 436: 437: get_metrics_as_dicts_with_keys(Keys, Config) -> 438: Vars = #{<<"keys">> => Keys}, 439: execute_command(<<"metric">>, <<"getMetricsAsDicts">>, Vars, Config). 440: 441: get_cluster_metrics_as_dicts(Config) -> 442: execute_command(<<"metric">>, <<"getClusterMetricsAsDicts">>, #{}, Config). 443: 444: get_cluster_metrics_as_dicts(Name, Keys, Nodes, Config) -> 445: Vars = #{<<"name">> => Name, <<"nodes">> => Nodes, <<"keys">> => Keys}, 446: execute_command(<<"metric">>, <<"getClusterMetricsAsDicts">>, Vars, Config). 447: 448: get_cluster_metrics_as_dicts_by_name(Name, Config) -> 449: Vars = #{<<"name">> => Name}, 450: execute_command(<<"metric">>, <<"getClusterMetricsAsDicts">>, Vars, Config). 451: 452: get_cluster_metrics_as_dicts_for_nodes(Nodes, Config) -> 453: Vars = #{<<"nodes">> => Nodes}, 454: execute_command(<<"metric">>, <<"getClusterMetricsAsDicts">>, Vars, Config). 455: 456: get_cluster_metrics_as_dicts_with_keys(Keys, Config) -> 457: Vars = #{<<"keys">> => Keys}, 458: execute_command(<<"metric">>, <<"getClusterMetricsAsDicts">>, Vars, Config). 459: 460: %% Helpers 461: 462: check_spiral_dict(Dict) -> 463: [#{<<"key">> := <<"count">>, <<"value">> := Count}, 464: #{<<"key">> := <<"one">>, <<"value">> := One}] = Dict, 465: ?assert(is_integer(Count)), 466: ?assert(is_integer(One)). 467: 468: values_are_integers(Map, Keys) -> 469: case lists:all(fun(Key) -> is_integer(maps:get(Key, Map)) end, Keys) of 470: true -> 471: ok; 472: false -> 473: ct:fail({values_are_integers, Keys, Map}) 474: end. 475: 476: metric_host_type() -> 477: binary:replace(domain_helper:host_type(), <<" ">>, <<"_">>, [global]). 478: 479: is_cets_enabled() -> 480: case rpc(mim(), mongoose_config, lookup_opt, [[internal_databases, cets]]) of 481: {ok, _} -> 482: true; 483: _ -> 484: false 485: end.