Skip to content

Commit 5c8d5f0

Browse files
authored
[Mellanox] Update spf test related to error status when sw control is enabled (sonic-net#16573) (sonic-net#19264)
[Mellanox] Update spf test related to error status when sw control is enabled
1 parent 0bea309 commit 5c8d5f0

5 files changed

Lines changed: 121 additions & 13 deletions

File tree

tests/common/platform/transceiver_utils.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,3 +389,60 @@ def is_passive_cable(sfp_eeprom_info):
389389
"CR" in spec_compliance.get("Extended Specification Compliance", " "):
390390
return True
391391
return False
392+
393+
394+
def get_passive_cable_port_list(dut):
395+
passive_cable_port_list = []
396+
cmd_show_eeprom = "sudo sfputil show eeprom -d"
397+
eeprom_infos = dut.command(cmd_show_eeprom)['stdout']
398+
eeprom_infos = parse_sfp_eeprom_infos(eeprom_infos)
399+
for port_name, eeprom_info in eeprom_infos.items():
400+
if is_passive_cable(eeprom_info):
401+
logging.info(f"{port_name} is passive cable")
402+
passive_cable_port_list.append(port_name)
403+
logging.info(f"Ports with passive cable are: {passive_cable_port_list}")
404+
return passive_cable_port_list
405+
406+
407+
def get_cmis_cable_ports_and_ver(dut):
408+
cmis_cable_port_to_version_map = {}
409+
cmd_show_eeprom = "sudo sfputil show eeprom -d"
410+
eeprom_infos = dut.command(cmd_show_eeprom)['stdout']
411+
eeprom_infos = parse_sfp_eeprom_infos(eeprom_infos)
412+
for port_name, eeprom_info in eeprom_infos.items():
413+
if 'CMIS Revision' in eeprom_info:
414+
logging.info(f"{port_name} is cmis cable")
415+
cmis_cable_port_to_version_map[port_name] = eeprom_info['CMIS Revision']
416+
logging.info(f"cmis_cable_port_to_version_map: {cmis_cable_port_to_version_map}")
417+
return cmis_cable_port_to_version_map
418+
419+
420+
def get_port_expected_error_state_for_mellanox_device_on_sw_control_enabled(
421+
intf, passive_cable_ports, cmis_cable_ports_and_ver):
422+
expected_state = 'OK'
423+
if intf in passive_cable_ports:
424+
# for active module, the expected state is OK
425+
# for cmis passive module, when cmis ver is 3.0, the expected state is ModuleLowPwr, else it is OK
426+
# for non cmis passive module, the expected state is 'Not supported'
427+
if intf in cmis_cable_ports_and_ver:
428+
expected_state = 'ModuleLowPwr' if cmis_cable_ports_and_ver[intf] == '3.0' else 'OK'
429+
else:
430+
expected_state = 'Not supported'
431+
logging.info(f"port {intf}, expected error state:{expected_state}")
432+
return expected_state
433+
434+
435+
def is_sw_control_enabled(duthost, port_index):
436+
"""
437+
@summary: This method is for checking if software control SAI attribute set to 1 in sai.profile
438+
@param: duthosts: duthosts fixture
439+
"""
440+
sw_control_enabled = False
441+
module_path = f'/sys/module/sx_core/asic0/module{int(port_index) - 1}'
442+
cmd_check_if_exist_conctrol_file = f'ls {module_path} | grep control'
443+
if duthost.shell(cmd_check_if_exist_conctrol_file, module_ignore_errors=True)['stdout']:
444+
cmd_get_control_value = f"sudo cat {module_path}/control"
445+
if duthost.shell(cmd_get_control_value)['stdout'] == "1":
446+
sw_control_enabled = True
447+
logging.info(f'The sw control enable of port index {port_index} is {sw_control_enabled}')
448+
return sw_control_enabled

tests/platform_tests/api/test_sfp.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
from tests.common.fixtures.conn_graph_facts import conn_graph_facts # noqa F401
1616
from tests.common.fixtures.duthost_utils import shutdown_ebgp # noqa F401
1717
from tests.common.platform.device_utils import platform_api_conn # noqa F401
18+
from tests.common.platform.transceiver_utils import is_sw_control_enabled,\
19+
get_port_expected_error_state_for_mellanox_device_on_sw_control_enabled
20+
from tests.common.mellanox_data import is_mellanox_device
21+
from collections import defaultdict
22+
1823

1924
from .platform_api_test_base import PlatformApiTestBase
2025

@@ -52,6 +57,10 @@ def setup(request, duthosts, enum_rand_one_per_hwsku_hostname,
5257
physical_port_index_map = get_physical_port_indices(duthost, physical_intfs)
5358
sfp_setup["physical_port_index_map"] = physical_port_index_map
5459

60+
sfp_setup["index_physical_port_map"] = defaultdict(list)
61+
for port, index in physical_port_index_map.items():
62+
sfp_setup["index_physical_port_map"][index].append(port)
63+
5564
sfp_port_indices = set([physical_port_index_map[intf] for intf in list(physical_port_index_map.keys())])
5665
sfp_setup["sfp_port_indices"] = sorted(sfp_port_indices)
5766

@@ -906,24 +915,33 @@ def test_power_override(self, duthosts, enum_rand_one_per_hwsku_hostname, localh
906915
"Transceiver {} power override data is incorrect".format(i))
907916
self.assert_expectations()
908917

918+
@pytest.mark.device_type('physical')
909919
def test_get_error_description(self, duthosts, enum_rand_one_per_hwsku_hostname, localhost,
910-
platform_api_conn): # noqa F811
920+
platform_api_conn, passive_cable_ports, cmis_cable_ports_and_ver): # noqa F811
911921
"""This function tests get_error_description() API (supported on 202106 and above)"""
912-
skip_release(duthosts[enum_rand_one_per_hwsku_hostname], ["201811", "201911", "202012"])
922+
duthost = duthosts[enum_rand_one_per_hwsku_hostname]
923+
skip_release(duthost, ["201811", "201911", "202012"])
913924

914925
for i in self.sfp_setup["sfp_test_port_indices"]:
915926
error_description = sfp.get_error_description(platform_api_conn, i)
916927
if self.expect(error_description is not None,
917928
"Unable to retrieve transceiver {} error description".format(i)):
918929
if "Not implemented" in error_description:
919930
pytest.skip("get_error_description isn't implemented. Skip the test")
920-
if "Not supported" in error_description:
931+
932+
expected_state = 'OK'
933+
if is_mellanox_device(duthost) and is_sw_control_enabled(duthost, i):
934+
intf = self.sfp_setup["index_physical_port_map"][i][0]
935+
expected_state = get_port_expected_error_state_for_mellanox_device_on_sw_control_enabled(
936+
intf, passive_cable_ports[duthost.hostname], cmis_cable_ports_and_ver[duthost.hostname])
937+
elif "Not supported" in error_description:
921938
logger.warning("test_get_error_description: Skipping transceiver {} as error description not "
922939
"supported on this port)".format(i))
923940
continue
924941
if self.expect(isinstance(error_description, str) or isinstance(error_description, str),
925942
"Transceiver {} error description appears incorrect".format(i)):
926-
self.expect(error_description == "OK", "Transceiver {} is not present".format(i))
943+
self.expect(error_description == expected_state,
944+
f"Transceiver {i} is not {expected_state}, actual state is:{error_description}.")
927945
self.assert_expectations()
928946

929947
def test_thermals(self, platform_api_conn): # noqa F811

tests/platform_tests/conftest.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
from tests.common.mellanox_data import is_mellanox_device
66
from .args.counterpoll_cpu_usage_args import add_counterpoll_cpu_usage_args
77
from tests.common.helpers.mellanox_thermal_control_test_helper import suspend_hw_tc_service, resume_hw_tc_service
8-
from tests.common.platform.transceiver_utils import get_ports_with_flat_memory
8+
from tests.common.platform.transceiver_utils import get_ports_with_flat_memory, \
9+
get_passive_cable_port_list, get_cmis_cable_ports_and_ver
910

1011

1112
@pytest.fixture(autouse=True, scope="module")
@@ -208,3 +209,21 @@ def port_list_with_flat_memory(duthosts):
208209
ports_with_flat_memory.update({dut.hostname: get_ports_with_flat_memory(dut)})
209210
logging.info(f"port list with flat memory: {ports_with_flat_memory}")
210211
return ports_with_flat_memory
212+
213+
214+
@pytest.fixture(scope="module")
215+
def passive_cable_ports(duthosts):
216+
passive_cable_ports = {}
217+
for dut in duthosts:
218+
passive_cable_ports.update({dut.hostname: get_passive_cable_port_list(dut)})
219+
logging.info(f"passive_cable_ports: {passive_cable_ports}")
220+
return passive_cable_ports
221+
222+
223+
@pytest.fixture(scope="module")
224+
def cmis_cable_ports_and_ver(duthosts):
225+
cmis_cable_ports_and_ver = {}
226+
for dut in duthosts:
227+
cmis_cable_ports_and_ver.update({dut.hostname: get_cmis_cable_ports_and_ver(dut)})
228+
logging.info(f"cmis_cable_ports_and_ver: {cmis_cable_ports_and_ver}")
229+
return cmis_cable_ports_and_ver

tests/platform_tests/sfp/test_sfputil.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
from tests.common.port_toggle import default_port_toggle_wait_time
1919
from tests.common.platform.transceiver_utils import I2C_WAIT_TIME_AFTER_SFP_RESET
2020
from tests.common.platform.interface_utils import get_physical_port_indices
21+
from tests.common.mellanox_data import is_mellanox_device
22+
from tests.common.platform.transceiver_utils import is_sw_control_enabled,\
23+
get_port_expected_error_state_for_mellanox_device_on_sw_control_enabled
24+
2125

2226
cmd_sfp_presence = "sudo sfputil show presence"
2327
cmd_sfp_eeprom = "sudo sfputil show eeprom"
@@ -335,10 +339,12 @@ def test_check_sfputil_presence(duthosts, enum_rand_one_per_hwsku_frontend_hostn
335339
assert parsed_presence[intf] == "Present", "Interface presence is not 'Present'"
336340

337341

342+
@pytest.mark.device_type('physical')
338343
@pytest.mark.parametrize("cmd_sfp_error_status",
339344
["sudo sfputil show error-status", "sudo sfputil show error-status --fetch-from-hardware"])
340345
def test_check_sfputil_error_status(duthosts, enum_rand_one_per_hwsku_frontend_hostname,
341-
enum_frontend_asic_index, conn_graph_facts, cmd_sfp_error_status, xcvr_skip_list):
346+
enum_frontend_asic_index, conn_graph_facts, cmd_sfp_error_status, xcvr_skip_list,
347+
passive_cable_ports, cmis_cable_ports_and_ver):
342348
"""
343349
@summary: Check SFP error status using 'sfputil show error-status'
344350
and 'sfputil show error-status --fetch-from-hardware'
@@ -355,14 +361,22 @@ def test_check_sfputil_error_status(duthosts, enum_rand_one_per_hwsku_frontend_h
355361
if "NOT implemented" in sfp_error_status['stdout']:
356362
pytest.skip("Skip test as error status isn't supported")
357363
parsed_presence = parse_output(sfp_error_status["stdout_lines"][2:])
364+
physical_port_index_map = get_physical_port_indices(duthost, conn_graph_facts["device_conn"][duthost.hostname])
358365
for intf in dev_conn:
359366
if intf not in xcvr_skip_list[duthost.hostname]:
360-
if "Not supported" in sfp_error_status['stdout']:
361-
logger.warning("test_check_sfputil_error_status: Skipping transceiver {} as error status not "
362-
"supported on this port)".format(intf))
367+
expected_state = 'OK'
368+
intf_index = physical_port_index_map[intf]
369+
if cmd_sfp_error_status == "sudo sfputil show error-status --fetch-from-hardware"\
370+
and is_mellanox_device(duthost) and is_sw_control_enabled(duthost, intf_index):
371+
expected_state = get_port_expected_error_state_for_mellanox_device_on_sw_control_enabled(
372+
intf, passive_cable_ports[duthost.hostname], cmis_cable_ports_and_ver[duthost.hostname])
373+
elif "Not supported" in sfp_error_status['stdout']:
374+
logger.warning("test_check_sfputil_error_status: Skipping transceiver {} as error status "
375+
"not supported on this port)".format(intf))
363376
continue
364-
assert intf in parsed_presence, "Interface is not in output of '{}'".format(cmd_sfp_presence)
365-
assert parsed_presence[intf] == "OK", "Interface error status is not 'OK'"
377+
assert intf in parsed_presence, "Interface is not in output of '{}'".format(cmd_sfp_error_status)
378+
assert parsed_presence[intf] == expected_state, \
379+
f"Interface {intf}'s error status is not {expected_state}, actual state is:{parsed_presence[intf]}."
366380

367381

368382
def test_check_sfputil_eeprom(duthosts, enum_rand_one_per_hwsku_frontend_hostname,

tests/platform_tests/sfp/util.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ def parse_output(output_lines):
1212
res = {}
1313
for line in output_lines:
1414
fields = line.split()
15-
if len(fields) != 2:
15+
if len(fields) < 2:
1616
continue
17-
res[fields[0]] = fields[1]
17+
res[fields[0]] = line.replace(fields[0], '').strip()
1818
return res
1919

2020

0 commit comments

Comments
 (0)