From 5da09bf5850b7de1272c0f29b287dc09fe7d9a54 Mon Sep 17 00:00:00 2001 From: Neetha John Date: Mon, 27 Apr 2020 15:34:35 -0700 Subject: [PATCH 1/4] Pytest PFCWD config test Signed-off-by: Neetha John --- tests/pfcwd/conftest.py | 76 ++++++ tests/pfcwd/files/__init__.py | 0 tests/pfcwd/files/pfcwd_helper.py | 235 ++++++++++++++++ .../templates/config_test_ignore_messages | 8 + tests/pfcwd/templates/pfc_config_params.json | 42 +++ tests/pfcwd/test_pfc_config.py | 257 ++++++++++++++++++ 6 files changed, 618 insertions(+) create mode 100644 tests/pfcwd/conftest.py create mode 100644 tests/pfcwd/files/__init__.py create mode 100644 tests/pfcwd/files/pfcwd_helper.py create mode 100644 tests/pfcwd/templates/config_test_ignore_messages create mode 100644 tests/pfcwd/templates/pfc_config_params.json create mode 100644 tests/pfcwd/test_pfc_config.py diff --git a/tests/pfcwd/conftest.py b/tests/pfcwd/conftest.py new file mode 100644 index 00000000000..448cb97f182 --- /dev/null +++ b/tests/pfcwd/conftest.py @@ -0,0 +1,76 @@ +import logging +import pytest +import os +from common.fixtures.conn_graph_facts import conn_graph_facts +from files.pfcwd_helper import TrafficPorts, set_pfc_timers, select_test_ports + +logger = logging.getLogger(__name__) + +def pytest_addoption(parser): + """ + Command line args specific for the pfcwd test + + Args: + parser: pytest parser object + + Returns: + None + + """ + parser.addoption('--warm-reboot', action='store', type=bool, default=False, + help='Warm reboot needs to be enabled or not') + +@pytest.fixture(scope="module") +def setup_pfc_test(duthost, ptfhost, conn_graph_facts): + """ + Sets up all the parameters needed for the PFC Watchdog tests + + Args: + duthost: AnsibleHost instance for DUT + ptfhost: AnsibleHost instance for PTF + conn_graph_facts: fixture that contains the parsed topology info + + Yields: + setup_info: dictionary containing pfc timers, generated test ports and selected test ports + """ + mg_facts = duthost.minigraph_facts(host=duthost.hostname)['ansible_facts'] + port_list = mg_facts['minigraph_ports'].keys() + ports = (' ').join(port_list) + neighbors = conn_graph_facts['device_conn'] + dut_facts = duthost.setup()['ansible_facts'] + dut_eth0_ip = dut_facts['ansible_eth0']['ipv4']['address'] + dut_eth0_mac = dut_facts['ansible_eth0']['macaddress'] + vlan_nw = None + + if mg_facts['minigraph_vlans']: + # gather all vlan specific info + vlan_addr = mg_facts['minigraph_vlan_interfaces'][0]['addr'] + vlan_prefix = mg_facts['minigraph_vlan_interfaces'][0]['prefixlen'] + vlan_dev = mg_facts['minigraph_vlan_interfaces'][0]['attachto'] + vlan_ips = duthost.get_ip_in_range(num=1, prefix="{}/{}".format(vlan_addr, vlan_prefix), exclude_ips=[vlan_addr])['ansible_facts']['generated_ips'] + vlan_nw = vlan_ips[0].split('/')[0] + + # set unique MACS to PTF interfaces + ptfhost.script("./scripts/change_mac.sh") + + duthost.shell("ip route flush {}/32".format(vlan_nw)) + duthost.shell("ip route add {}/32 dev {}".format(vlan_nw, vlan_dev)) + + # build the port list for the test + tp_handle = TrafficPorts(mg_facts, neighbors, vlan_nw) + test_ports = tp_handle.build_port_list() + # select a subset of ports from the generated port list + selected_ports = select_test_ports(test_ports) + + setup_info = { 'test_ports': test_ports, + 'selected_test_ports': selected_ports, + 'pfc_timers' : set_pfc_timers() + } + + # set poll interval + duthost.command("pfcwd interval {}".format(setup_info['pfc_timers']['pfc_wd_poll_time'])) + + yield setup_info + + logger.info("--- Starting Pfcwd ---") + duthost.command("pfcwd start_default") diff --git a/tests/pfcwd/files/__init__.py b/tests/pfcwd/files/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/pfcwd/files/pfcwd_helper.py b/tests/pfcwd/files/pfcwd_helper.py new file mode 100644 index 00000000000..65c9b6a5e74 --- /dev/null +++ b/tests/pfcwd/files/pfcwd_helper.py @@ -0,0 +1,235 @@ +import datetime +import ipaddress + +class TrafficPorts(object): + """ Generate a list of ports needed for the PFC Watchdog test""" + def __init__(self, mg_facts, neighbors, vlan_nw): + """ + Args: + mg_facts (dict): parsed minigraph info + neighbors (list): 'device_conn' info from connection graph facts + vlan_nw (string): ip in the vlan range specified in the DUT + + """ + self.mg_facts = mg_facts + self.bgp_info = self.mg_facts['minigraph_bgp'] + self.port_idx_info = self.mg_facts['minigraph_port_indices'] + self.pc_info = self.mg_facts['minigraph_portchannels'] + self.vlan_info = self.mg_facts['minigraph_vlans'] + self.neighbors = neighbors + self.vlan_nw = vlan_nw + self.test_ports = dict() + self.pfc_wd_rx_port = None + self.pfc_wd_rx_port_addr = None + self.pfc_wd_rx_neighbor_addr = None + self.pfc_wd_rx_port_id = None + + def build_port_list(self): + """ + Generate a list of ports to be used for the test. For T0 topology, the + port list is built parsing the portchannel and vlan info and for T1, + port list is constructed from the interface info + """ + if self.mg_facts['minigraph_interfaces']: + self.parse_intf_list() + elif self.mg_facts['minigraph_portchannels']: + self.parse_pc_list() + if self.mg_facts['minigraph_vlans']: + self.test_ports.update(self.parse_vlan_list()) + return self.test_ports + + def parse_intf_list(self): + """ + Built the port info from the ports in 'minigraph_interfaces'. The constructed + port info is a dict with a port as the key (transmit port) and value contains + all the info associated with this port (its fanout neighbor, receive port, receive + ptf id, transmit ptf id, neighbor addr etc). + The first port in the list is assumed to be the Rx port. The rest + of the ports will use this port as the Rx port while populating their dict + info. The selected Rx port when used as a transmit port will use the next port in + the list as its associated Rx port + """ + pfc_wd_test_port = None + first_pair = False + for intf in self.mg_facts['minigraph_interfaces']: + if ipaddress.ip_address(unicode(intf['addr'])).version != 4: + continue + # first port + if not self.pfc_wd_rx_port: + self.pfc_wd_rx_port = intf['attachto'] + self.pfc_wd_rx_port_addr = intf['addr'] + self.pfc_wd_rx_port_id = self.port_idx_info[self.pfc_wd_rx_port] + elif not pfc_wd_test_port: + # second port + first_pair = True + + # populate info for all ports except the first one + if first_pair or pfc_wd_test_port: + pfc_wd_test_port = intf['attachto'] + pfc_wd_test_port_addr = intf['addr'] + pfc_wd_test_port_id = self.port_idx_info[pfc_wd_test_port] + pfc_wd_test_neighbor_addr = None + + for item in self.bgp_info: + if ipaddress.ip_address(unicode(item['addr'])).version != 4: + continue + if not self.pfc_wd_rx_neighbor_addr and item['peer_addr'] == self.pfc_wd_rx_port_addr: + self.pfc_wd_rx_neighbor_addr = item['addr'] + if item['peer_addr'] == pfc_wd_test_port_addr: + pfc_wd_test_neighbor_addr = item['addr'] + + self.test_ports[pfc_wd_test_port] = {'test_neighbor_addr': pfc_wd_test_neighbor_addr, + 'rx_port': [self.pfc_wd_rx_port], + 'rx_neighbor_addr': self.pfc_wd_rx_neighbor_addr, + 'peer_device': self.neighbors[pfc_wd_test_port]['peerdevice'], + 'test_port_id': pfc_wd_test_port_id, + 'rx_port_id': [self.pfc_wd_rx_port_id], + 'test_port_type': 'interface' + } + # populate info for the first port + if first_pair: + self.test_ports[self.pfc_wd_rx_port] = {'test_neighbor_addr': self.pfc_wd_rx_neighbor_addr, + 'rx_port': [pfc_wd_test_port], + 'rx_neighbor_addr': pfc_wd_test_neighbor_addr, + 'peer_device': self.neighbors[self.pfc_wd_rx_port]['peerdevice'], + 'test_port_id': self.pfc_wd_rx_port_id, + 'rx_port_id': [pfc_wd_test_port_id], + 'test_port_type': 'interface' + } + + first_pair = False + + def parse_pc_list(self): + """ + Built the port info from the ports in portchannel. The constructed + port info is a dict with a port as the key (transmit port) and value contains + all the info associated with this port (its fanout neighbor, receive ports, receive + ptf ids, transmit ptf ids, neighbor portchannel addr, its own portchannel addr etc). + The first port in the list is assumed to be the Rx port. The rest + of the ports will use this port as the Rx port while populating their dict + info. The selected Rx port when used as a transmit port will use the next port in + the list as its associated Rx port + """ + pfc_wd_test_port = None + first_pair = False + for item in self.mg_facts['minigraph_portchannel_interfaces']: + if ipaddress.ip_address(unicode(item['addr'])).version != 4: + continue + pc = item['attachto'] + # first port + if not self.pfc_wd_rx_port: + self.pfc_wd_rx_portchannel = pc + self.pfc_wd_rx_port = self.pc_info[pc]['members'] + self.pfc_wd_rx_port_addr = item['addr'] + self.pfc_wd_rx_port_id = [self.port_idx_info[port] for port in self.pfc_wd_rx_port] + elif not pfc_wd_test_port: + # second port + first_pair = True + + # populate info for all ports except the first one + if first_pair or pfc_wd_test_port: + pfc_wd_test_portchannel = pc + pfc_wd_test_port = self.pc_info[pc]['members'] + pfc_wd_test_port_addr = item['addr'] + pfc_wd_test_port_id = [self.port_idx_info[port] for port in pfc_wd_test_port] + pfc_wd_test_neighbor_addr = None + + for bgp_item in self.bgp_info: + if ipaddress.ip_address(unicode(bgp_item['addr'])).version != 4: + continue + if not self.pfc_wd_rx_neighbor_addr and bgp_item['peer_addr'] == self.pfc_wd_rx_port_addr: + self.pfc_wd_rx_neighbor_addr = bgp_item['addr'] + if bgp_item['peer_addr'] == pfc_wd_test_port_addr: + pfc_wd_test_neighbor_addr = bgp_item['addr'] + + for port in pfc_wd_test_port: + self.test_ports[port] = {'test_neighbor_addr': pfc_wd_test_neighbor_addr, + 'rx_port': self.pfc_wd_rx_port, + 'rx_neighbor_addr': self.pfc_wd_rx_neighbor_addr, + 'peer_device': self.neighbors[port]['peerdevice'], + 'test_port_id': self.port_idx_info[port], + 'rx_port_id': self.pfc_wd_rx_port_id, + 'test_portchannel_members': pfc_wd_test_port_id, + 'test_port_type': 'portchannel' + } + # populate info for the first port + if first_pair: + for port in self.pfc_wd_rx_port: + self.test_ports[port] = {'test_neighbor_addr': self.pfc_wd_rx_neighbor_addr, + 'rx_port': pfc_wd_test_port, + 'rx_neighbor_addr': pfc_wd_test_neighbor_addr, + 'peer_device': self.neighbors[port]['peerdevice'], + 'test_port_id': self.port_idx_info[port], + 'rx_port_id': pfc_wd_test_port_id, + 'test_portchannel_members': self.pfc_wd_rx_port_id, + 'test_port_type': 'portchannel' + } + + first_pair = False + + def parse_vlan_list(self): + """ + Add vlan specific port info to the already populated port info dict. + Each vlan interface will be the key and value contains + all the info associated with this port (receive fanout neighbor, receive port receive + ptf id, transmit ptf id, neighbor addr etc). + + Args: + None + + Returns: + temp_ports (dict): port info constructed from the vlan interfaces + """ + temp_ports = dict() + vlan_members = self.vlan_info[self.vlan_info.keys()[0]]['members'] + for item in vlan_members: + temp_ports[item] = {'test_neighbor_addr': self.vlan_nw, + 'rx_port': self.pfc_wd_rx_port, + 'rx_neighbor_addr': self.pfc_wd_rx_neighbor_addr, + 'peer_device': self.neighbors[item]['peerdevice'], + 'test_port_id': self.port_idx_info[item], + 'rx_port_id': self.pfc_wd_rx_port_id, + 'test_port_type': 'vlan' + } + + return temp_ports + +def set_pfc_timers(): + """ + Set PFC timers + + Args: + None + + Returns: + pfc_timers (dict) + """ + pfc_timers = {'pfc_wd_detect_time': 400, + 'pfc_wd_restore_time': 400, + 'pfc_wd_restore_time_large': 3000, + 'pfc_wd_poll_time': 400 + } + return pfc_timers + + +def select_test_ports(test_ports): + """ + Select a subset of ports from the generated port info + + Args: + test_ports (dict): Constructed port info + + Returns: + selected_ports (dict): random port info or set of ports matching seed + """ + selected_ports = dict() + seed = int(datetime.datetime.today().day) + for key, value in test_ports.items(): + if (int(value['test_port_id']) % 15) == (seed % 15): + selected_ports.update({key:value}) + + if not selected_ports: + random_port = test_ports.keys()[0] + selected_ports[random_port] = test_ports[random_port] + + return selected_ports diff --git a/tests/pfcwd/templates/config_test_ignore_messages b/tests/pfcwd/templates/config_test_ignore_messages new file mode 100644 index 00000000000..b93ffa1530b --- /dev/null +++ b/tests/pfcwd/templates/config_test_ignore_messages @@ -0,0 +1,8 @@ +r, ".* Port counter .* not implemented" +r, ".* Port counter .* not supported" +r, ".* Invalid port counter .*" +r, ".* Unknown.*" +r, ".* SAI_STATUS_ATTR_NOT_SUPPORT.*" +r, ".* snmp.*" +r, ".* Trying to remove nonexisting queue from flex counter .*" +r, ".* ERR ntpd.*routing socket reports: No buffer space available.*" diff --git a/tests/pfcwd/templates/pfc_config_params.json b/tests/pfcwd/templates/pfc_config_params.json new file mode 100644 index 00000000000..000d6029b8b --- /dev/null +++ b/tests/pfcwd/templates/pfc_config_params.json @@ -0,0 +1,42 @@ +{ + "pfc_wd_fwd_action": { + "pfc_wd_action": "forward", + "pfc_wd_detection_time": 4000, + "pfc_wd_restoration_time": 5000 + }, + "pfc_wd_invalid_action": { + "pfc_wd_action": "invalid", + "pfc_wd_detection_time": 4000, + "pfc_wd_restoration_time": 5000 + }, + "pfc_wd_invalid_detect_time": { + "pfc_wd_action": "forward", + "pfc_wd_detection_time": "400a", + "pfc_wd_restoration_time": 5000 + }, + "pfc_wd_low_detect_time": { + "pfc_wd_action": "forward", + "pfc_wd_detection_time": 40, + "pfc_wd_restoration_time": 5000 + }, + "pfc_wd_high_detect_time": { + "pfc_wd_action": "forward", + "pfc_wd_detection_time": 4000000, + "pfc_wd_restoration_time": 5000 + }, + "pfc_wd_invalid_restore_time": { + "pfc_wd_action": "forward", + "pfc_wd_detection_time": 4000, + "pfc_wd_restoration_time": "500c" + }, + "pfc_wd_low_restore_time": { + "pfc_wd_action": "forward", + "pfc_wd_detection_time": 4000, + "pfc_wd_restoration_time": 50 + }, + "pfc_wd_high_restore_time": { + "pfc_wd_action": "forward", + "pfc_wd_detection_time": 4000, + "pfc_wd_restoration_time": 50000000 + } +} diff --git a/tests/pfcwd/test_pfc_config.py b/tests/pfcwd/test_pfc_config.py new file mode 100644 index 00000000000..879de896649 --- /dev/null +++ b/tests/pfcwd/test_pfc_config.py @@ -0,0 +1,257 @@ +import json +import os +import pytest +import logging + +from common.helpers.assertions import pytest_assert +from common.plugins.loganalyzer.loganalyzer import LogAnalyzer + +logger = logging.getLogger(__name__) + +DUT_RUN_DIR = "/home/admin/pfc_wd_tests" +TEMPLATES_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "templates") +TMP_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "testrun") +CONFIG_TEST_EXPECT_INVALID_ACTION_RE = ".* Invalid PFC Watchdog action .*" +CONFIG_TEST_EXPECT_INVALID_DETECT_TIME_RE = ".* Failed to parse PFC Watchdog .* detection_time .*" +CONFIG_TEST_EXPECT_INVALID_RESTORE_TIME_RE = ".* Failed to parse PFC Watchdog .* restoration_time .*" + +pytestmark = [pytest.mark.disable_loganalyzer] # disable automatic fixture and invoke within each test + +def create_run_dir(): + """ + Creates a temp run dir 'testrun' within the pfcwd folder + """ + try: + os.mkdir(TMP_DIR) + except OSError as err: + pytest.fail("Failed to create a temp run dir: {}".format(str(err))) + +def generate_cfg_templates(test_port): + """ + Build all the config templates that will be used for the config validation test + + Args: + test_port (string): a random port selected from the test port list + + Returns: + cfg_params (dict): all config templates + """ + create_run_dir() + with open(os.path.join(TEMPLATES_DIR, "pfc_config_params.json"), "r") as read_file: + cfg_params = json.load(read_file) + + for key in cfg_params: + write_file = key + write_params = dict() + write_params["PFC_WD"] = { test_port: { "action": cfg_params[key]["pfc_wd_action"], + "detection_time": cfg_params[key]["pfc_wd_detection_time"], + "restoration_time": cfg_params[key]["pfc_wd_restoration_time"] + } + } + # create individual template files for each test + with open(os.path.join(TMP_DIR, "{}.json".format(write_file)), "w") as wfile: + json.dump(write_params, wfile) + + return cfg_params + +def copy_templates_to_dut(duthost, cfg_params): + """ + Copy all the templates created to the DUT + + Args: + duthost (AnsibleHost): instance + cfg_params (dict): all config templates + + Returns: + None + """ + duthost.shell("mkdir -p {}".format(DUT_RUN_DIR)) + for key in cfg_params: + src_file = os.path.join(TMP_DIR, "{}.json".format(key)) + duthost.copy(src=src_file, dest="{}/{}.json".format(DUT_RUN_DIR, key)) + +def cfg_teardown(duthost): + """ + Cleans up the DUT temp dir and temp dir on the host after the module run + + Args: + duthost (AnsibleHost): instance + + Returns: + None + """ + if os.path.exists(TMP_DIR): + os.system("rm -rf {}".format(TMP_DIR)) + duthost.shell("rm -rf {}".format(DUT_RUN_DIR)) + +@pytest.fixture(scope='class', autouse=True) +def cfg_setup(setup_pfc_test, duthost): + """ + Class level automatic fixture. Prior to the test run, create all the templates + needed for each individual test and copy them on the DUT. + After the all the test cases are done, clean up temp dir on DUT and host + + Args: + setup_pfc_test: module fixture defined in module conftest.py + duthost: instance of AnsibleHost class + """ + setup_info = setup_pfc_test + pfc_wd_test_port = setup_info['test_ports'].keys()[0] + logger.info("Creating json templates for all config tests") + cfg_params = generate_cfg_templates(pfc_wd_test_port) + logger.info("Copying templates over to the DUT") + copy_templates_to_dut(duthost, cfg_params) + + yield + logger.info("--- Start running config tests ---") + + logger.info("--- Clean up config dir from DUT ---") + cfg_teardown(duthost) + + +@pytest.fixture(scope='function', autouse=True) +def stop_pfcwd(duthost): + """ + Fixture that stops PFC Watchdog before each test run + + Args: + duthost: instance of AnsibleHost class + + Returns: + None + """ + logger.info("--- Stop Pfcwd --") + duthost.command("pfcwd stop") + + +@pytest.mark.usefixtures('cfg_setup') +class TestPfcConfig(object): + """ + Test case definition and helper function class + """ + def execute_test(self, duthost, marker, ignore_regex=None, expect_regex=None, expect_errors=False): + """ + Helper function that loads each template on the DUT and verifies the expected behavior + + Args: + duthost (AnsibleHost): instance + marker (string): marker prefix name to be inserted in the syslog + ignore_regex (string): file containing regexs to be ignored by loganalyzer + expect_regex (string): regex pattern that is expected to be present in the syslog + expect_erros (bool): if the test expects an error msg in the syslog or not. Default: False + + Returns: + None + """ + loganalyzer = LogAnalyzer(ansible_host=duthost, marker_prefix=marker) + + if ignore_regex: + ignore_file = os.path.join(TEMPLATES_DIR, ignore_regex) + reg_exp = loganalyzer.parse_regexp_file(src=ignore_file) + loganalyzer.ignore_regex.extend(reg_exp) + + if expect_regex: + loganalyzer.expect_regex = [] + loganalyzer.expect_regex.extend(expect_regex) + + loganalyzer.match_regex = [] + with loganalyzer(fail=not expect_errors): + cmd = "sonic-cfggen -j {}/{}.json --write-to-db".format(DUT_RUN_DIR, marker) + out = duthost.command(cmd) + pytest_assert(out["rc"] == 0, "Failed to execute cmd {}: Error: {}".format(cmd, out["stderr"])) + + def test_forward_action_cfg(self, duthost): + """ + Tests if the config gets loaded properly for a valid cfg template + + Args: + duthost(AnsibleHost): instance + + Returns: + None + """ + self.execute_test(duthost, "pfc_wd_fwd_action", "config_test_ignore_messages") + + def test_invalid_action_cfg(self, duthost): + """ + Tests for syslog error when invalid action is configured + + Args: + duthost(AnsibleHost): instance + + Returns: + None + """ + self.execute_test(duthost, "pfc_wd_invalid_action", None, [CONFIG_TEST_EXPECT_INVALID_ACTION_RE], True) + + def test_invalid_detect_time_cfg(self, duthost): + """ + Tests for syslog error when invalid detect time is configured + + Args: + duthost(AnsibleHost): instance + + Returns: + None + """ + self.execute_test(duthost, "pfc_wd_invalid_detect_time", None, [CONFIG_TEST_EXPECT_INVALID_DETECT_TIME_RE], True) + + def test_low_detect_time_cfg(self, duthost): + """ + Tests for syslog error when detect time < lower bound is configured + + Args: + duthost(AnsibleHost): instance + + Returns: + None + """ + self.execute_test(duthost, "pfc_wd_low_detect_time", None, [CONFIG_TEST_EXPECT_INVALID_DETECT_TIME_RE], True) + + def test_high_detect_time_cfg(self, duthost): + """ + Tests for syslog error when detect time > higher bound is configured + + Args: + duthost(AnsibleHost): instance + + Returns: + None + """ + self.execute_test(duthost, "pfc_wd_high_detect_time", None, [CONFIG_TEST_EXPECT_INVALID_DETECT_TIME_RE], True) + + def test_invalid_restore_time_cfg(self, duthost): + """ + Tests for syslog error when invalid restore time is configured + + Args: + duthost(AnsibleHost): instance + + Returns: + None + """ + self.execute_test(duthost, "pfc_wd_invalid_restore_time", None, [CONFIG_TEST_EXPECT_INVALID_RESTORE_TIME_RE], True) + + def test_low_restore_time_cfg(self, duthost): + """ + Tests for syslog error when restore time < lower bound is configured + + Args: + duthost(AnsibleHost): instance + + Returns: + None + """ + self.execute_test(duthost, "pfc_wd_low_restore_time", None, [CONFIG_TEST_EXPECT_INVALID_RESTORE_TIME_RE], True) + + def test_high_restore_time_cfg(self, duthost): + """ + Tests for syslog error when restore time > higher bound is configured + + Args: + duthost(AnsibleHost): instance + + Returns: + None + """ + self.execute_test(duthost, "pfc_wd_high_restore_time", None, [CONFIG_TEST_EXPECT_INVALID_RESTORE_TIME_RE], True) From b945ad023acc6c97e8c6730e5aa4cbfc86baf452 Mon Sep 17 00:00:00 2001 From: Neetha John Date: Mon, 4 May 2020 13:18:41 -0700 Subject: [PATCH 2/4] Address LGTM Signed-off-by: Neetha John --- tests/pfcwd/conftest.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/pfcwd/conftest.py b/tests/pfcwd/conftest.py index 448cb97f182..3521913f290 100644 --- a/tests/pfcwd/conftest.py +++ b/tests/pfcwd/conftest.py @@ -1,6 +1,5 @@ import logging import pytest -import os from common.fixtures.conn_graph_facts import conn_graph_facts from files.pfcwd_helper import TrafficPorts, set_pfc_timers, select_test_ports From be945c5fa2ae03c8ab7930e371b538e91bcb71ff Mon Sep 17 00:00:00 2001 From: Neetha John Date: Mon, 4 May 2020 13:21:28 -0700 Subject: [PATCH 3/4] Rename marker to syslog_marker Signed-off-by: Neetha John --- tests/pfcwd/test_pfc_config.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/pfcwd/test_pfc_config.py b/tests/pfcwd/test_pfc_config.py index 879de896649..7c7d7656486 100644 --- a/tests/pfcwd/test_pfc_config.py +++ b/tests/pfcwd/test_pfc_config.py @@ -129,13 +129,13 @@ class TestPfcConfig(object): """ Test case definition and helper function class """ - def execute_test(self, duthost, marker, ignore_regex=None, expect_regex=None, expect_errors=False): + def execute_test(self, duthost, syslog_marker, ignore_regex=None, expect_regex=None, expect_errors=False): """ Helper function that loads each template on the DUT and verifies the expected behavior Args: duthost (AnsibleHost): instance - marker (string): marker prefix name to be inserted in the syslog + syslog_marker (string): marker prefix name to be inserted in the syslog ignore_regex (string): file containing regexs to be ignored by loganalyzer expect_regex (string): regex pattern that is expected to be present in the syslog expect_erros (bool): if the test expects an error msg in the syslog or not. Default: False @@ -143,7 +143,7 @@ def execute_test(self, duthost, marker, ignore_regex=None, expect_regex=None, ex Returns: None """ - loganalyzer = LogAnalyzer(ansible_host=duthost, marker_prefix=marker) + loganalyzer = LogAnalyzer(ansible_host=duthost, marker_prefix=syslog_marker) if ignore_regex: ignore_file = os.path.join(TEMPLATES_DIR, ignore_regex) @@ -156,7 +156,7 @@ def execute_test(self, duthost, marker, ignore_regex=None, expect_regex=None, ex loganalyzer.match_regex = [] with loganalyzer(fail=not expect_errors): - cmd = "sonic-cfggen -j {}/{}.json --write-to-db".format(DUT_RUN_DIR, marker) + cmd = "sonic-cfggen -j {}/{}.json --write-to-db".format(DUT_RUN_DIR, syslog_marker) out = duthost.command(cmd) pytest_assert(out["rc"] == 0, "Failed to execute cmd {}: Error: {}".format(cmd, out["stderr"])) From 9ad57041b6461f1e8a747d78b536f43b69aa2b3c Mon Sep 17 00:00:00 2001 From: Neetha John Date: Thu, 7 May 2020 10:03:44 -0700 Subject: [PATCH 4/4] Separate out verbose comments Signed-off-by: Neetha John --- tests/pfcwd/files/pfcwd_helper.py | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/tests/pfcwd/files/pfcwd_helper.py b/tests/pfcwd/files/pfcwd_helper.py index 65c9b6a5e74..c2fa58e9286 100644 --- a/tests/pfcwd/files/pfcwd_helper.py +++ b/tests/pfcwd/files/pfcwd_helper.py @@ -26,8 +26,9 @@ def __init__(self, mg_facts, neighbors, vlan_nw): def build_port_list(self): """ - Generate a list of ports to be used for the test. For T0 topology, the - port list is built parsing the portchannel and vlan info and for T1, + Generate a list of ports to be used for the test + + For T0 topology, the port list is built parsing the portchannel and vlan info and for T1, port list is constructed from the interface info """ if self.mg_facts['minigraph_interfaces']: @@ -40,12 +41,12 @@ def build_port_list(self): def parse_intf_list(self): """ - Built the port info from the ports in 'minigraph_interfaces'. The constructed - port info is a dict with a port as the key (transmit port) and value contains - all the info associated with this port (its fanout neighbor, receive port, receive - ptf id, transmit ptf id, neighbor addr etc). - The first port in the list is assumed to be the Rx port. The rest - of the ports will use this port as the Rx port while populating their dict + Built the port info from the ports in 'minigraph_interfaces' + + The constructed port info is a dict with a port as the key (transmit port) and value contains + all the info associated with this port (its fanout neighbor, receive port, receive ptf id, + transmit ptf id, neighbor addr etc). The first port in the list is assumed to be the Rx port. + The rest of the ports will use this port as the Rx port while populating their dict info. The selected Rx port when used as a transmit port will use the next port in the list as its associated Rx port """ @@ -101,8 +102,9 @@ def parse_intf_list(self): def parse_pc_list(self): """ - Built the port info from the ports in portchannel. The constructed - port info is a dict with a port as the key (transmit port) and value contains + Built the port info from the ports in portchannel + + The constructed port info is a dict with a port as the key (transmit port) and value contains all the info associated with this port (its fanout neighbor, receive ports, receive ptf ids, transmit ptf ids, neighbor portchannel addr, its own portchannel addr etc). The first port in the list is assumed to be the Rx port. The rest @@ -170,9 +172,9 @@ def parse_pc_list(self): def parse_vlan_list(self): """ Add vlan specific port info to the already populated port info dict. - Each vlan interface will be the key and value contains - all the info associated with this port (receive fanout neighbor, receive port receive - ptf id, transmit ptf id, neighbor addr etc). + + Each vlan interface will be the key and value contains all the info associated with this port + (receive fanout neighbor, receive port receive ptf id, transmit ptf id, neighbor addr etc). Args: None