diff --git a/tests/common/platform/interface_utils.py b/tests/common/platform/interface_utils.py index ec38e4cae09..51e06a1185a 100644 --- a/tests/common/platform/interface_utils.py +++ b/tests/common/platform/interface_utils.py @@ -3,7 +3,10 @@ This script contains re-usable functions for checking status of interfaces on SONiC. """ + +import re import logging +from natsort import natsorted from transceiver_utils import all_transceivers_detected @@ -121,3 +124,28 @@ def get_port_map(dut, asic_index=None): port_mapping[k] = [v] return port_mapping + +def get_physical_port_indices(duthost): + """Returns list of physical port numbers of the DUT""" + physical_port_indices = set() + + intf_facts = duthost.interface_facts()['ansible_facts']['ansible_interface_facts'] + phy_port = re.compile(r'^Ethernet\d+$') + phy_intfs = [k for k in intf_facts.keys() if re.match(phy_port, k)] + phy_intfs = natsorted(phy_intfs) + logging.info("physical interfaces = {}".format(phy_intfs)) + + for asic_index in duthost.get_frontend_asic_ids(): + # Get interfaces of this asic + interface_list = get_port_map(duthost, asic_index) + interfaces_per_asic = {k:v for k, v in interface_list.items() if k in phy_intfs} + #logging.info("ASIC index={} interfaces = {}".format(asic_index, interfaces_per_asic)) + for intf in interfaces_per_asic: + if asic_index is not None: + cmd = 'sonic-db-cli -n asic{} CONFIG_DB HGET "PORT|{}" index'.format(asic_index, intf) + else: + cmd = 'sonic-db-cli CONFIG_DB HGET "PORT|{}" index'.format(intf) + index = duthost.command(cmd)["stdout"] + physical_port_indices.add(int(index)) + #logging.info("$$$ physical port indices = {}".format(physical_port_indices)) + return list(physical_port_indices) diff --git a/tests/platform_tests/api/test_chassis.py b/tests/platform_tests/api/test_chassis.py index fdb247d2e2a..ae51fa50406 100644 --- a/tests/platform_tests/api/test_chassis.py +++ b/tests/platform_tests/api/test_chassis.py @@ -6,10 +6,11 @@ from tests.common.helpers.assertions import pytest_assert from tests.common.helpers.platform_api import chassis, module +from tests.common.fixtures.conn_graph_facts import conn_graph_facts from tests.common.utilities import get_inventory_files from tests.common.utilities import get_host_visible_vars from tests.common.utilities import skip_version -from tests.common.platform.interface_utils import get_port_map +from tests.common.platform.interface_utils import get_physical_port_indices from platform_api_test_base import PlatformApiTestBase @@ -54,12 +55,19 @@ ONIE_TLVINFO_TYPE_CODE_VENDOR_EXT = '0xFD' # Vendor Extension ONIE_TLVINFO_TYPE_CODE_CRC32 = '0xFE' # CRC-32 +# get_physical_port_indices() is wrapped around pytest fixture with module +# scope because this function can be quite time consuming based upon the +# number of ports on the DUT +@pytest.fixture(scope="module") +def physical_port_indices(duthosts, enum_rand_one_per_hwsku_hostname): + duthost = duthosts[enum_rand_one_per_hwsku_hostname] + return get_physical_port_indices(duthost) @pytest.fixture(scope="class") def gather_facts(request, duthosts): request.cls.inv_files = get_inventory_files(request) -@pytest.mark.usefixtures("gather_facts") +@pytest.mark.usefixtures("gather_facts", "physical_port_indices") class TestChassisApi(PlatformApiTestBase): """Platform API test cases for the Chassis class""" inv_files = None @@ -362,7 +370,7 @@ def test_thermals(self, duthosts, enum_rand_one_per_hwsku_hostname, localhost, p self.expect(thermal and thermal == thermal_list[i], "Thermal {} is incorrect".format(i)) self.assert_expectations() - def test_sfps(self, duthosts, enum_rand_one_per_hwsku_hostname, localhost, platform_api_conn): + def test_sfps(self, duthosts, enum_rand_one_per_hwsku_hostname, localhost, platform_api_conn, physical_port_indices): duthost = duthosts[enum_rand_one_per_hwsku_hostname] if duthost.is_supervisor_node(): pytest.skip("skipping for supervisor node") @@ -371,16 +379,8 @@ def test_sfps(self, duthosts, enum_rand_one_per_hwsku_hostname, localhost, platf except: pytest.fail("num_sfps is not an integer") list_sfps = [] - if duthost.facts.get("interfaces"): - intfs = duthost.facts.get("interfaces") - for intf in intfs: - index_list = [int(x) for x in duthost.facts["interfaces"][intf]['index'].split(",")] - list_sfps.extend(set(index_list)) - else: - int_list = get_port_map(duthost, 'all') - for k, v in int_list.items(): - list_sfps.extend(v) - list_sfps.sort() + list_sfps = physical_port_indices + logging.info("Physical port indices = {}".format(list_sfps)) if duthost.facts.get("chassis"): expected_num_sfps = len(duthost.facts.get("chassis").get('sfps')) pytest_assert(num_sfps == expected_num_sfps, diff --git a/tests/platform_tests/api/test_sfp.py b/tests/platform_tests/api/test_sfp.py index be1b7876906..36b0a2285da 100644 --- a/tests/platform_tests/api/test_sfp.py +++ b/tests/platform_tests/api/test_sfp.py @@ -1,13 +1,12 @@ import ast import logging -import re import pytest from tests.common.helpers.assertions import pytest_assert from tests.common.helpers.platform_api import sfp from tests.common.utilities import skip_version -from tests.common.platform.interface_utils import get_port_map +from tests.common.platform.interface_utils import get_physical_port_indices from tests.common.utilities import wait_until from platform_api_test_base import PlatformApiTestBase @@ -108,31 +107,25 @@ class TestSfpApi(PlatformApiTestBase): num_sfps = None candidate_sfp = None + # get_physical_port_indices() is wrapped around pytest fixture with module + # scope because this function can be quite time consuming based upon the + # number of ports on the DUT + @pytest.fixture(scope="module") + def physical_port_indices(self, duthosts, enum_rand_one_per_hwsku_hostname): + duthost = duthosts[enum_rand_one_per_hwsku_hostname] + return get_physical_port_indices(duthost) + # This fixture would probably be better scoped at the class level, but # it relies on the platform_api_conn fixture, which is scoped at the function # level, so we must do the same here to prevent a scope mismatch. @pytest.fixture(scope="function", autouse=True) - def setup(self, request, duthosts, enum_rand_one_per_hwsku_hostname, platform_api_conn): + def setup(self, request, duthosts, enum_rand_one_per_hwsku_hostname, platform_api_conn, physical_port_indices): duthost = duthosts[enum_rand_one_per_hwsku_hostname] if duthost.is_supervisor_node(): pytest.skip("skipping for supervisor node") self.skip_absent_sfp = request.config.getoption("--skip-absent-sfp") - internal_intf = re.compile(r'^Ethernet-BP|^Ethernet-IB') - self.list_sfps = [] - # get expected data from platform.json if not present get from port_config.ini - if duthost.facts.get("interfaces"): - intfs = duthost.facts.get("interfaces") - for intf in intfs: - if re.match(internal_intf, intf): - logging.debug("skipping internal interface {}".format(intf)) - continue - index_list = [int(x) for x in duthost.facts["interfaces"][intf]['index'].split(",")] - self.list_sfps.extend(set(index_list)) - else: - int_list = get_port_map(duthost, 'all') - for k, v in int_list.items(): - self.list_sfps.extend(v) - self.list_sfps.sort() + self.list_sfps = physical_port_indices + #logging.info("physical_port_indices {}".format(physical_port_indices)) self.candidate_sfp = [] if self.skip_absent_sfp: # Skip absent SFP if option "--skip-absent-sfp" set to True