diff --git a/counterpoll/main.py b/counterpoll/main.py index 9bb45a4539..451e9fc563 100644 --- a/counterpoll/main.py +++ b/counterpoll/main.py @@ -259,38 +259,38 @@ def disable(): # Policer counter commands @cli.group() -def policer(): +@click.pass_context +def policer(ctx): """ Policer counter commands """ + ctx.obj = ConfigDBConnector() + ctx.obj.connect() @policer.command() +@click.pass_context @click.argument('poll_interval') -def interval(poll_interval): +def interval(ctx, poll_interval): """ Set policer counter query interval """ - configdb = ConfigDBConnector() - configdb.connect() policer_info = {} if poll_interval is not None: policer_info['POLL_INTERVAL'] = poll_interval - configdb.mod_entry("FLEX_COUNTER_TABLE", POLICER, policer_info) + ctx.obj.mod_entry("FLEX_COUNTER_TABLE", POLICER, policer_info) @policer.command() -def enable(): +@click.pass_context +def enable(ctx): """ Enable policer counter query """ - configdb = ConfigDBConnector() - configdb.connect() policer_info = {} policer_info['FLEX_COUNTER_STATUS'] = ENABLE - configdb.mod_entry("FLEX_COUNTER_TABLE", POLICER, policer_info) + ctx.obj.mod_entry("FLEX_COUNTER_TABLE", POLICER, policer_info) @policer.command() -def disable(): +@click.pass_context +def disable(ctx): """ Disable policer counter query """ - configdb = ConfigDBConnector() - configdb.connect() policer_info = {} policer_info['FLEX_COUNTER_STATUS'] = DISABLE - configdb.mod_entry("FLEX_COUNTER_TABLE", POLICER, policer_info) + ctx.obj.mod_entry("FLEX_COUNTER_TABLE", POLICER, policer_info) # ACL counter commands @cli.group() diff --git a/scripts/policerstat b/scripts/policerstat index 3889995388..15aac9e778 100755 --- a/scripts/policerstat +++ b/scripts/policerstat @@ -1,243 +1,259 @@ -#!/usr/bin/env python3 - -##################################################################### -# -# policerstat is a tool for summarizing policer counter statistics. -# -##################################################################### - -import json -import argparse -import datetime -import sys -import os -import time -from collections import namedtuple, OrderedDict -from natsort import natsorted -from tabulate import tabulate -from utilities_common.netstat import ns_diff, table_as_json, STATUS_NA, format_number_with_comma -from utilities_common.cli import json_serial, UserCache -from swsscommon.swsscommon import SonicV2Connector - -pstat_fields = ( - "totalpacket", - "totalbytes", - "gtotalpacket", - "gtotalbytes", - "ytotalpacket", - "ytotalbytes", - "rtotalpacket", - "rtotalbytes" -) - -PStats = namedtuple("PStats", pstat_fields) - -header = [ - 'Policer', - 'Total Packets', - 'Total Bytes', - 'Green Packets', - 'Green Bytes', - 'Yellow Packets', - 'Yellow Bytes', - 'Red Packets', - 'Red Bytes' -] - -def build_json(cnstat): - def policers_stats(policer_name, counters): - return { - policer_name: { - "totalpacket": counters.get("totalpacket", "N/A"), - "totalbytes": counters.get("totalbytes", "N/A"), - "gtotalpacket": counters.get("gtotalpacket", "N/A"), - "gtotalbytes": counters.get("gtotalbytes", "N/A"), - "ytotalpacket": counters.get("ytotalpacket", "N/A"), - "ytotalbytes": counters.get("ytotalbytes", "N/A"), - "rtotalpacket": counters.get("rtotalpacket", "N/A"), - "rtotalbytes": counters.get("rtotalbytes", "N/A") - } - } - - out = {} - for policer_name, counters in cnstat.items(): - if policer_name == 'time': - continue - out.update(policers_stats(policer_name, counters)) - return out - -counter_names = ( - 'SAI_POLICER_STAT_PACKETS', - 'SAI_POLICER_STAT_ATTR_BYTES', - 'SAI_POLICER_STAT_GREEN_PACKETS', - 'SAI_POLICER_STAT_GREEN_BYTES', - 'SAI_POLICER_STAT_YELLOW_PACKETS', - 'SAI_POLICER_STAT_YELLOW_BYTES', - 'SAI_POLICER_STAT_RED_PACKETS', - 'SAI_POLICER_STAT_RED_BYTES' -) - -COUNTER_TABLE_PREFIX = "COUNTERS:" -COUNTERS_POLICER_NAME_MAP = "COUNTERS_POLICER_NAME_MAP" - -class Policerstat: - def __init__(self): - self.db = SonicV2Connector(use_unix_socket_path=False) - self.db.connect(self.db.COUNTERS_DB) - self.db.connect(self.db.APPL_DB) - - def get_cnstat(self, policer=None): - """ - Get the counters info from database. - """ - def get_counters(policer, table_id): - """ - Get the counters from specific table. - """ - fields = [STATUS_NA] * len(pstat_fields) - for pos, counter_name in enumerate(counter_names): - full_table_id = f"{COUNTER_TABLE_PREFIX}{table_id}" - counter_data = self.db.get(self.db.COUNTERS_DB, full_table_id, counter_name) - if counter_data: - fields[pos] = str(counter_data) - cntr = PStats._make(fields)._asdict() - cntr['policername'] = policer - return cntr - - - cnstat_dict = OrderedDict(time=datetime.datetime.now()) - - counter_policer_name_map = self.db.get_all(self.db.COUNTERS_DB, COUNTERS_POLICER_NAME_MAP) - if counter_policer_name_map is None: - print(f"No {COUNTERS_POLICER_NAME_MAP} in the DB!") - sys.exit(1) - - if policer and policer not in counter_policer_name_map: - print(f"Policer {policer} missing from {COUNTERS_POLICER_NAME_MAP}! Make sure it exists.") - sys.exit(2) - - if policer: - cnstat_dict[policer] = get_counters(policer, counter_policer_name_map[policer]) - return cnstat_dict - - for policer in natsorted(counter_policer_name_map): - cnstat_dict[policer] = get_counters(policer, counter_policer_name_map[policer]) - return cnstat_dict - - def cnstat_print(self, policer, cnstat_dict, use_json): - """ - Print the cnstat. - """ - table = [] - for key, data in cnstat_dict.items(): - if key == 'time': - continue - table.append(( - data.get('policername', 'N/A'), - data.get('totalpacket', 'N/A'), - data.get('totalbytes', 'N/A'), - data.get('gtotalpacket', 'N/A'), - data.get('gtotalbytes', 'N/A'), - data.get('ytotalpacket', 'N/A'), - data.get('ytotalbytes', 'N/A'), - data.get('rtotalpacket', 'N/A'), - data.get('rtotalbytes', 'N/A') - )) - if table: - print(tabulate(table, header, tablefmt='simple', stralign='right')) - print() - elif use_json: - print(json.dumps({policer: cnstat_dict}, indent=4)) - else: - print("No data available for the given policer.") - - def cnstat_diff_print(self, policer, cnstat_new_dict, cnstat_old_dict, use_json): - """ - Print the difference between two cnstat results. - """ - table = [] - json_output = {policer: {}} - - for key, cntr in cnstat_new_dict.items(): - if key == 'time': - continue - old_cntr = cnstat_old_dict.get(key) - if old_cntr: - table.append((key, - ns_diff(cntr['totalpacket'], old_cntr['totalpacket']), - ns_diff(cntr['totalbytes'], old_cntr['totalbytes']), - ns_diff(cntr['gtotalpacket'], old_cntr['gtotalpacket']), - ns_diff(cntr['gtotalbytes'], old_cntr['gtotalbytes']), - ns_diff(cntr['ytotalpacket'], old_cntr['ytotalpacket']), - ns_diff(cntr['ytotalbytes'], old_cntr['ytotalbytes']), - ns_diff(cntr['rtotalpacket'], old_cntr['rtotalpacket']), - ns_diff(cntr['rtotalbytes'], old_cntr['rtotalbytes']))) - else: - table.append((key, - format_number_with_comma(cntr['totalpacket']), - format_number_with_comma(cntr['totalbytes']), - format_number_with_comma(cntr['gtotalpacket']), - format_number_with_comma(cntr['gtotalbytes']), - format_number_with_comma(cntr['ytotalpacket']), - format_number_with_comma(cntr['ytotalbytes']), - format_number_with_comma(cntr['rtotalpacket']), - format_number_with_comma(cntr['rtotalbytes']))) - if table: - if use_json: - print(table_as_json(table, header)) - else: - print(tabulate(table, header, tablefmt='simple', stralign='right')) - print() - - -def main(): - parser = argparse.ArgumentParser( - description='Display the policer counters', - formatter_class=argparse.RawTextHelpFormatter, - epilog=""" - Examples: - policerstat -c - policerstat -j - policerstat -p span_policer - """ - ) - - parser.add_argument('-c', '--clear', action='store_true', help='Copy & clear stats') - parser.add_argument('-j', '--json', action='store_true', help='Display in JSON format') - parser.add_argument('-p', '--policer', type=str, help='Show stats for a single policer') - parser.add_argument('-v', '--version', action='version', version='%(prog)s 1.0') - args = parser.parse_args() - - cache = UserCache() - - cnstat_dir = cache.get_directory() - cnstat_fqn_file = os.path.join(cnstat_dir, 'policerstat') - - policerstat = Policerstat() - cnstat_dict = policerstat.get_cnstat(policer=args.policer) - - if args.clear: - json.dump(cnstat_dict, open(cnstat_fqn_file, 'w'), default=json_serial) - print("Cleared counters") - sys.exit(0) - - if args.json: - # JSON output handling - print(json.dumps(build_json(cnstat_dict), default=json_serial)) - else: - if os.path.isfile(cnstat_fqn_file): - try: - cnstat_cached_dict = json.load(open(cnstat_fqn_file, 'r')) - json_output = {} - if args.json: - json_output[args.policer].update({"cached_time":cnstat_cached_dict.get('time')}) - json_output.update(policerstat.cnstat_diff_print(args.policer, cnstat_dict, cnstat_cached_dict, args.json)) - else: - policerstat.cnstat_diff_print(args.policer, cnstat_dict, cnstat_cached_dict, args.json) - except IOError as e: - print(e.errno, e) - else: - policerstat.cnstat_print(args.policer, cnstat_dict, args.json) - -if __name__ == "__main__": - main() +#!/usr/bin/env python3 + +##################################################################### +# +# policerstat is a tool for summarizing policer counter statistics. +# +##################################################################### + +import json +import argparse +import datetime +import sys +import os +import time +from collections import namedtuple, OrderedDict +from natsort import natsorted +from tabulate import tabulate + +try: + if os.environ["UTILITIES_UNIT_TESTING"] == "2": + modules_path = os.path.join(os.path.dirname(__file__), "..") + tests_path = os.path.join(modules_path, "tests") + sys.path.insert(0, modules_path) + sys.path.insert(0, tests_path) + import mock_tables.dbconnector + if os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] == "multi_asic": + import mock_tables.mock_multi_asic + mock_tables.dbconnector.load_namespace_config() +except KeyError: + pass + +from utilities_common.netstat import ns_diff, STATUS_NA, format_number_with_comma, table_as_json +from utilities_common import multi_asic as multi_asic_util +from utilities_common import constants +from utilities_common.cli import json_serial, UserCache +from swsscommon.swsscommon import ConfigDBConnector, SonicV2Connector + +pstat_fields = ( + "totalpacket", + "totalbytes", + "gtotalpacket", + "gtotalbytes", + "ytotalpacket", + "ytotalbytes", + "rtotalpacket", + "rtotalbytes" +) + +PStats = namedtuple("PStats", pstat_fields) + +header = [ + 'Policer', + 'Total Packets', + 'Total Bytes', + 'Green Packets', + 'Green Bytes', + 'Yellow Packets', + 'Yellow Bytes', + 'Red Packets', + 'Red Bytes' +] + +def build_json(cnstat): + def policers_stats(policer_name, counters): + return { + policer_name: { + "totalpacket": counters.get("totalpacket", "N/A"), + "totalbytes": counters.get("totalbytes", "N/A"), + "gtotalpacket": counters.get("gtotalpacket", "N/A"), + "gtotalbytes": counters.get("gtotalbytes", "N/A"), + "ytotalpacket": counters.get("ytotalpacket", "N/A"), + "ytotalbytes": counters.get("ytotalbytes", "N/A"), + "rtotalpacket": counters.get("rtotalpacket", "N/A"), + "rtotalbytes": counters.get("rtotalbytes", "N/A") + } + } + + out = {} + for policer_name, counters in cnstat.items(): + if policer_name == 'time': + continue + out.update(policers_stats(policer_name, counters)) + return out + +counter_names = ( + 'SAI_POLICER_STAT_PACKETS', + 'SAI_POLICER_STAT_ATTR_BYTES', + 'SAI_POLICER_STAT_GREEN_PACKETS', + 'SAI_POLICER_STAT_GREEN_BYTES', + 'SAI_POLICER_STAT_YELLOW_PACKETS', + 'SAI_POLICER_STAT_YELLOW_BYTES', + 'SAI_POLICER_STAT_RED_PACKETS', + 'SAI_POLICER_STAT_RED_BYTES' +) + +COUNTER_TABLE_PREFIX = "COUNTERS:" +COUNTERS_POLICER_NAME_MAP = "COUNTERS_POLICER_NAME_MAP" + +class Policerstat: + def __init__(self): + self.db = SonicV2Connector(host='127.0.0.1') + self.db.connect(self.db.COUNTERS_DB) + + def get_cnstat(self, policer=None): + """ + Get the counters info from database. + """ + def get_counters(policer, table_id): + """ + Get the counters from specific table. + """ + fields = [STATUS_NA] * len(pstat_fields) + for pos, counter_name in enumerate(counter_names): + full_table_id = f"{COUNTER_TABLE_PREFIX}{table_id}" + counter_data = self.db.get(self.db.COUNTERS_DB, full_table_id, counter_name) + if counter_data: + fields[pos] = str(counter_data) + cntr = PStats._make(fields)._asdict() + cntr['policername'] = policer + return cntr + + + cnstat_dict = OrderedDict(time=datetime.datetime.now()) + + counter_policer_name_map = self.db.get_all(self.db.COUNTERS_DB, COUNTERS_POLICER_NAME_MAP) + if counter_policer_name_map is None: + print(f"No {COUNTERS_POLICER_NAME_MAP} in the DB!") + sys.exit(1) + + if policer and policer not in counter_policer_name_map: + print(f"Policer {policer} missing from {COUNTERS_POLICER_NAME_MAP}! Make sure it exists.") + sys.exit(2) + + if policer: + cnstat_dict[policer] = get_counters(policer, counter_policer_name_map[policer]) + return cnstat_dict + + for policer in natsorted(counter_policer_name_map): + cnstat_dict[policer] = get_counters(policer, counter_policer_name_map[policer]) + return cnstat_dict + + def cnstat_print(self, policer, cnstat_dict, use_json): + """ + Print the cnstat. + """ + table = [] + for key, data in cnstat_dict.items(): + if key == 'time': + continue + table.append(( + data.get('policername', 'N/A'), + data.get('totalpacket', 'N/A'), + data.get('totalbytes', 'N/A'), + data.get('gtotalpacket', 'N/A'), + data.get('gtotalbytes', 'N/A'), + data.get('ytotalpacket', 'N/A'), + data.get('ytotalbytes', 'N/A'), + data.get('rtotalpacket', 'N/A'), + data.get('rtotalbytes', 'N/A') + )) + if table: + print(tabulate(table, header, tablefmt='simple', stralign='right')) + print() + elif use_json: + print(json.dumps({policer: cnstat_dict}, indent=4)) + else: + print("No data available for the given policer.") + + def cnstat_diff_print(self, policer, cnstat_new_dict, cnstat_old_dict, use_json): + """ + Print the difference between two cnstat results. + """ + table = [] + json_output = {policer: {}} + + for key, cntr in cnstat_new_dict.items(): + if key == 'time': + continue + old_cntr = cnstat_old_dict.get(key) + if old_cntr: + table.append((key, + ns_diff(cntr['totalpacket'], old_cntr['totalpacket']), + ns_diff(cntr['totalbytes'], old_cntr['totalbytes']), + ns_diff(cntr['gtotalpacket'], old_cntr['gtotalpacket']), + ns_diff(cntr['gtotalbytes'], old_cntr['gtotalbytes']), + ns_diff(cntr['ytotalpacket'], old_cntr['ytotalpacket']), + ns_diff(cntr['ytotalbytes'], old_cntr['ytotalbytes']), + ns_diff(cntr['rtotalpacket'], old_cntr['rtotalpacket']), + ns_diff(cntr['rtotalbytes'], old_cntr['rtotalbytes']))) + else: + table.append((key, + format_number_with_comma(cntr['totalpacket']), + format_number_with_comma(cntr['totalbytes']), + format_number_with_comma(cntr['gtotalpacket']), + format_number_with_comma(cntr['gtotalbytes']), + format_number_with_comma(cntr['ytotalpacket']), + format_number_with_comma(cntr['ytotalbytes']), + format_number_with_comma(cntr['rtotalpacket']), + format_number_with_comma(cntr['rtotalbytes']))) + if table: + if use_json: + print(table_as_json(table, header)) + else: + print(tabulate(table, header, tablefmt='simple', stralign='right')) + print() + + +def main(): + parser = argparse.ArgumentParser( + description='Display the policer counters', + formatter_class=argparse.RawTextHelpFormatter, + epilog=""" + Examples: + policerstat -c + policerstat -j + policerstat -p span_policer + """ + ) + + parser.add_argument('-c', '--clear', action='store_true', help='Copy & clear stats') + parser.add_argument('-j', '--json', action='store_true', help='Display in JSON format') + parser.add_argument('-p', '--policer', type=str, help='Show stats for a single policer') + args = parser.parse_args() + + cache = UserCache() + + cnstat_dir = cache.get_directory() + cnstat_fqn_file = os.path.join(cnstat_dir, 'policerstat') + + policerstat = Policerstat() + cnstat_dict = policerstat.get_cnstat(policer=args.policer) + + if args.clear: + json.dump(cnstat_dict, open(cnstat_fqn_file, 'w'), default=json_serial) + print("Cleared counters") + sys.exit(0) + + if args.json: + # JSON output handling + print(json.dumps(build_json(cnstat_dict), default=json_serial)) + + else: + if os.path.isfile(cnstat_fqn_file): + try: + cnstat_cached_dict = json.load(open(cnstat_fqn_file, 'r')) + json_output = {} + if args.json: + json_output[args.policer].update({"cached_time":cnstat_cached_dict.get('time')}) + json_output.update(policerstat.cnstat_diff_print(args.policer, cnstat_dict, cnstat_cached_dict, args.json)) + else: + policerstat.cnstat_diff_print(args.policer, cnstat_dict, cnstat_cached_dict, args.json) + except IOError as e: + print(e.errno, e) + else: + policerstat.cnstat_print(args.policer, cnstat_dict, args.json) + sys.exit(0) + +if __name__ == "__main__": + main() diff --git a/show/main.py b/show/main.py index 5ec07c695b..b3dfd50951 100755 --- a/show/main.py +++ b/show/main.py @@ -2266,7 +2266,7 @@ def policer(policer_name, counter, verbose): cmd = ['policerstat'] if policer_name is not None: - cmd += ["-p", str(policer_name)] + cmd += ["-p", str(policer_name)] run_command(cmd, display_cmd=verbose) else: cmd = ['acl-loader', 'show', 'policer'] diff --git a/tests/counterpoll_input/config_db.json b/tests/counterpoll_input/config_db.json index 38cde7c15e..3749efeb3b 100644 --- a/tests/counterpoll_input/config_db.json +++ b/tests/counterpoll_input/config_db.json @@ -790,6 +790,9 @@ }, "FLOW_CNT_ROUTE": { "FLEX_COUNTER_STATUS": "enable" + }, + "POLICER": { + "FLEX_COUNTER_STATUS": "enable" } }, "PORT": { @@ -2668,5 +2671,13 @@ "pool": "ingress_lossless_pool", "size": "56368" } + }, + "POLICER|policer0": { + "meter_type":"packets", + "mode":"sr_tcm", + "color": "aware", + "cir":"700", + "cbs":"700", + "red_packet_action":"drop" } } diff --git a/tests/counterpoll_test.py b/tests/counterpoll_test.py index 6c165498c5..b199de7349 100644 --- a/tests/counterpoll_test.py +++ b/tests/counterpoll_test.py @@ -30,6 +30,7 @@ TUNNEL_STAT 3000 enable FLOW_CNT_TRAP_STAT 10000 enable FLOW_CNT_ROUTE_STAT 10000 enable +POLICER 10000 enable """ expected_counterpoll_show_dpu = """Type Interval (in ms) Status @@ -192,6 +193,18 @@ def test_update_route_flow_counter_status(self, status): table = db.cfgdb.get_table('FLEX_COUNTER_TABLE') assert status == table["FLOW_CNT_ROUTE"]["FLEX_COUNTER_STATUS"] + @pytest.mark.parametrize("status", ["disable", "enable"]) + def test_update_policer_counter_status(self, status): + runner = CliRunner() + db = Db() + + result = runner.invoke(counterpoll.cli.commands["policer"].commands[status], [], obj=db.cfgdb) + print(result.exit_code, result.output) + assert result.exit_code == 0 + + table = db.cfgdb.get_table('FLEX_COUNTER_TABLE') + assert status == table["POLICER"]["FLEX_COUNTER_STATUS"] + def test_update_trap_counter_interval(self): runner = CliRunner() db = Db() @@ -277,6 +290,58 @@ def test_update_eni_interval(self, mock_get_platform_info): table = db.cfgdb.get_table('FLEX_COUNTER_TABLE') assert test_interval == table["ENI"]["POLL_INTERVAL"] + def test_update_policer_counter_interval(self): + runner = CliRunner() + db = Db() + test_interval = "20000" + + result = runner.invoke(counterpoll.cli.commands["policer"].commands["interval"], [test_interval], + obj=db.cfgdb) + print(result.exit_code, result.output) + assert result.exit_code == 0 + + table = db.cfgdb.get_table('FLEX_COUNTER_TABLE') + assert test_interval == table["POLICER"]["POLL_INTERVAL"] + + test_interval = "500" + result = runner.invoke(counterpoll.cli.commands["policer"].commands["interval"], [test_interval], + obj=db.cfgdb) + expected = "Invalid value for \"POLL_INTERVAL\": 500 is not in the valid range of 1000 to 30000." + assert result.exit_code == 2 + assert expected in result.output + + test_interval = "40000" + result = runner.invoke(counterpoll.cli.commands["policer"].commands["interval"], [test_interval], + obj=db.cfgdb) + + expected = "Invalid value for \"POLL_INTERVAL\": 40000 is not in the valid range of 1000 to 30000." + assert result.exit_code == 2 + assert expected in result.output + + @pytest.mark.parametrize("status", ["disable", "enable"]) + def test_update_policer_counter_status(self, status): + runner = CliRunner() + db = Db() + + result = runner.invoke(counterpoll.cli.commands["policer"].commands[status], [], obj=db.cfgdb) + assert result.exit_code == 0 + + table = db.cfgdb.get_table('FLEX_COUNTER_TABLE') + assert status == table["POLICER"]["FLEX_COUNTER_STATUS"] + + def test_update_policer_interval(self): + runner = CliRunner() + db = Db() + test_interval = "20000" + + result = runner.invoke(counterpoll.cli.commands["policer"].commands["interval"], [test_interval], obj=db.cfgdb) + print(result.exit_code, result.output) + assert result.exit_code == 0 + + table = db.cfgdb.get_table("FLEX_COUNTER_TABLE") + assert test_interval == table["POLICER"]["POLL_INTERVAL"] + + @classmethod def teardown_class(cls): print("TEARDOWN") diff --git a/tests/mock_tables/config_db.json b/tests/mock_tables/config_db.json index 3deca74255..8f1165a463 100644 --- a/tests/mock_tables/config_db.json +++ b/tests/mock_tables/config_db.json @@ -1789,6 +1789,10 @@ "POLL_INTERVAL": "1000", "FLEX_COUNTER_STATUS": "enable" }, + "FLEX_COUNTER_TABLE|POLICER": { + "POLL_INTERVAL": "10000", + "FLEX_COUNTER_STATUS": "enable" + }, "PFC_WD|Ethernet0": { "action": "drop", "detection_time": "600", @@ -2739,6 +2743,14 @@ "src_port": "Ethernet40,Ethernet48", "direction": "RX" }, + "POLICER|policer0": { + "meter_type":"packets", + "mode":"sr_tcm", + "color": "aware", + "cir":"700", + "cbs":"700", + "red_packet_action":"drop" + }, "FABRIC_MONITOR|FABRIC_MONITOR_DATA": { "monCapacityThreshWarn": "100", "monErrThreshCrcCells": "1", diff --git a/tests/mock_tables/counters_db.json b/tests/mock_tables/counters_db.json index 9e553c2901..cb354af157 100644 --- a/tests/mock_tables/counters_db.json +++ b/tests/mock_tables/counters_db.json @@ -2510,5 +2510,18 @@ "COUNTERS:oid:0x1600000000035f":{ "SAI_COUNTER_STAT_PACKETS": 1000, "SAI_COUNTER_STAT_BYTES": 25000 + }, + "COUNTERS_POLICER_NAME_MAP": { + "policer0": "oid:0x1200000000040a" + }, + "COUNTERS:oid:0x1200000000040a": { + "SAI_POLICER_STAT_ATTR_BYTES": "1000", + "SAI_POLICER_STAT_GREEN_BYTES": "2000", + "SAI_POLICER_STAT_GREEN_PACKETS": "3000", + "SAI_POLICER_STAT_PACKETS": "4000", + "SAI_POLICER_STAT_RED_BYTES": "5000", + "SAI_POLICER_STAT_RED_PACKETS": "6000", + "SAI_POLICER_STAT_YELLOW_BYTES": "7000", + "SAI_POLICER_STAT_YELLOW_PACKETS": "8000" } } diff --git a/tests/policerstat_test.py b/tests/policerstat_test.py new file mode 100755 index 0000000000..12df85d4fa --- /dev/null +++ b/tests/policerstat_test.py @@ -0,0 +1,96 @@ +import os + +from click.testing import CliRunner +import show.main as show +import clear.main as clear +from .utils import get_result_and_return_code +from utilities_common.cli import UserCache + +test_path = os.path.dirname(os.path.abspath(__file__)) +modules_path = os.path.dirname(test_path) +scripts_path = os.path.join(modules_path, "scripts") + +show_policer_counters_output = """\ + Policer Total Packets Total Bytes Green Packets Green Bytes Yellow Packets Yellow Bytes Red Packets Red Bytes +--------- --------------- ------------- --------------- ------------- ---------------- -------------- ------------- ----------- + policer0 4000 1000 3000 2000 8000 7000 6000 5000 + +""" + +show_policer_counters_output_diff = """\ + Policer Total Packets Total Bytes Green Packets Green Bytes Yellow Packets Yellow Bytes Red Packets Red Bytes +--------- --------------- ------------- --------------- ------------- ---------------- -------------- ------------- ----------- + policer0 0 0 0 0 0 0 0 0 + +""" + +def del_cached_stats(): + cache = UserCache("policerstat") + cache.remove_all() + +def policer_clear(expected_output): + del_cached_stats() + + return_code, result = get_result_and_return_code( + ['policerstat', '-c'] + ) + + assert return_code == 0 + + return_code, result = get_result_and_return_code( + ['policerstat'] + ) + + result_stat = [s for s in result.split("\n") if "Last cached" not in s] + print(result_stat) + print("result_stat") + + expected = expected_output.split("\n") + print(expected) + print("expected") + assert result_stat == expected + del_cached_stats() + + +class TestPolicerstat(object): + @classmethod + def setup_class(cls): + print("SETUP") + os.environ["PATH"] += os.pathsep + scripts_path + os.environ["UTILITIES_UNIT_TESTING"] = "2" + del_cached_stats() + + + def test_policer_counters(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands['policer'], ['policer0', '--counter']) + assert result.exit_code == 0 + assert result.output == show_policer_counters_output + + def test_policerstat(self): + return_code, result = get_result_and_return_code(['policerstat']) + assert return_code == 0 + assert result == show_policer_counters_output + + def test_policer_counters_with_clear(self): + runner = CliRunner() + result = runner.invoke(clear.cli.commands['policercounters'], []) + assert result.exit_code == 0 + assert result.output == "Cleared counters\n\n" + result = runner.invoke( + show.cli.commands["policer"], + ["--counter"] + ) + assert result.output == show_policer_counters_output_diff + + def test_policer_clear(self): + policer_clear(show_policer_counters_output_diff) + + @classmethod + def teardown_class(cls): + print("TEARDOWN") + os.environ["PATH"] = os.pathsep.join( + os.environ["PATH"].split(os.pathsep)[:-1] + ) + os.environ["UTILITIES_UNIT_TESTING"] = "0" + del_cached_stats()