Skip to content

Commit

Permalink
[sonic-pcie] Add UT for pcie_common.py (sonic-net#293)
Browse files Browse the repository at this point in the history
Description
Add unit testcases for pcie_common.py
Code coverage improved to 86%.

Motivation and Context
To improve code coverage for pcie_common.py
  • Loading branch information
ArunSaravananBalachandran committed Aug 31, 2022
1 parent 211d6bc commit 9400720
Showing 1 changed file with 214 additions and 0 deletions.
214 changes: 214 additions & 0 deletions tests/pcie_common_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
import os
import sys
import yaml
from sonic_platform_base.sonic_pcie.pcie_common import PcieUtil

if sys.version_info.major == 3:
from unittest import mock
BUILTINS = 'builtins'
else:
import mock
BUILTINS = '__builtin__'

tests_dir = os.path.dirname(os.path.abspath(__file__))
pcie_config_file = os.path.join(tests_dir, 'pcie.yaml')

lspci_output = '''\
00:01.0 PCI A
00:02.0 PCI B
00:02.1 PCI C
01:00.0 PCI D
'''

lspci_ID_output = '''\
00:01.0 0001: 0000:000a
00:02.0 0002: 0000:000b
00:02.1 0003: 0000:000c
01:00.0 0004: 0000:000d
'''

pci_sysfs_paths = [
'/sys/bus/pci/devices/0000:00:01.0',
'/sys/bus/pci/devices/0000:00:02.0',
'/sys/bus/pci/devices/0000:00:02.1',
'/sys/bus/pci/devices/0000:01:00.0'
]

pcie_device_list = [
{'bus': '00', 'dev': '01', 'fn': '0', 'id': '000a', 'name': 'PCI A'},
{'bus': '00', 'dev': '02', 'fn': '0', 'id': '000b', 'name': 'PCI B'},
{'bus': '00', 'dev': '02', 'fn': '1', 'id': '000c', 'name': 'PCI C'},
{'bus': '01', 'dev': '00', 'fn': '0', 'id': '000d', 'name': 'PCI D'},
]

pcie_check_output = [
{'bus': '00', 'dev': '01', 'fn': '0', 'id': '000a', 'name': 'PCI A', 'result': 'Passed'},
{'bus': '00', 'dev': '02', 'fn': '0', 'id': '000b', 'name': 'PCI B', 'result': 'Passed'},
{'bus': '00', 'dev': '02', 'fn': '1', 'id': '000c', 'name': 'PCI C', 'result': 'Passed'},
{'bus': '01', 'dev': '00', 'fn': '0', 'id': '000d', 'name': 'PCI D', 'result': 'Passed'}
]

pcie_aer_correctable_content = '''\
RxErr 0
BadTLP 1
BadDLLP 2
Rollover 3
Timeout 4
NonFatalErr 5
CorrIntErr 6
HeaderOF 7
TOTAL_ERR_COR 28
'''

pcie_aer_fatal_content = '''\
Undefined 0
DLP 1
SDES 2
TLP 3
FCP 4
CmpltTO 5
CmpltAbrt 6
UnxCmplt 7
RxOF 8
MalfTLP 9
ECRC 0
UnsupReq 1
ACSViol 2
UncorrIntErr 3
BlockedTLP 4
AtomicOpBlocked 5
TLPBlockedErr 6
TOTAL_ERR_FATAL 66
'''

pcie_aer_nonfatal_content = '''\
Undefined 0
DLP 1
SDES 2
TLP 3
FCP 4
CmpltTO 5
CmpltAbrt 6
UnxCmplt 7
RxOF 8
MalfTLP 9
ECRC 0
UnsupReq 1
ACSViol 2
UncorrIntErr 3
BlockedTLP 4
AtomicOpBlocked 5
TLPBlockedErr 6
TOTAL_ERR_NONFATAL 66
'''

pcie_aer_stats = {
'correctable': {
'RxErr': '0', 'BadTLP': '1', 'BadDLLP': '2', 'Rollover': '3',
'Timeout': '4', 'NonFatalErr': '5', 'CorrIntErr': '6', 'HeaderOF': '7',
'TOTAL_ERR_COR': '28'
},
'fatal': {
'Undefined': '0', 'DLP': '1', 'SDES': '2', 'TLP': '3', 'FCP': '4',
'CmpltTO': '5', 'CmpltAbrt': '6', 'UnxCmplt': '7', 'RxOF': '8',
'MalfTLP': '9', 'ECRC': '0', 'UnsupReq': '1', 'ACSViol': '2',
'UncorrIntErr': '3', 'BlockedTLP': '4', 'AtomicOpBlocked': '5',
'TLPBlockedErr': '6', 'TOTAL_ERR_FATAL': '66'
},
'non_fatal': {
'Undefined': '0', 'DLP': '1', 'SDES': '2', 'TLP': '3', 'FCP': '4',
'CmpltTO': '5', 'CmpltAbrt': '6', 'UnxCmplt': '7', 'RxOF': '8',
'MalfTLP': '9', 'ECRC': '0', 'UnsupReq': '1', 'ACSViol': '2',
'UncorrIntErr': '3', 'BlockedTLP': '4', 'AtomicOpBlocked': '5',
'TLPBlockedErr': '6', 'TOTAL_ERR_NONFATAL': '66'
},
}


class TestPcieCommon:

@mock.patch('subprocess.Popen')
def test_get_pcie_devices(self, subprocess_popen_mock):

def subprocess_popen_side_effect(*args, **kwargs):
if args[0] == 'sudo lspci':
output = lspci_output.splitlines()
elif args[0] == 'sudo lspci -n':
output = lspci_ID_output.splitlines()

popen_mock = mock.Mock()
popen_attributes = {
'returncode': 0,
'communicate.return_value': ('', ''),
'stdout.readlines.return_value': output
}
popen_mock.configure_mock(**popen_attributes)
return popen_mock

subprocess_popen_mock.side_effect = subprocess_popen_side_effect
pcieutil = PcieUtil(tests_dir)
result = pcieutil.get_pcie_device()
assert result == pcie_device_list

@mock.patch('os.path.exists')
def test_get_pcie_check(self, os_path_exists_mock):

def os_path_exists_side_effect(*args):
return bool(args[0] in pci_sysfs_paths)

os_path_exists_mock.side_effect = os_path_exists_side_effect
pcieutil = PcieUtil(tests_dir)
sample_pcie_config = yaml.dump(pcie_device_list)

open_mock = mock.mock_open(read_data=sample_pcie_config)
with mock.patch('{}.open'.format(BUILTINS), open_mock):
result = pcieutil.get_pcie_check()
open_mock.assert_called_once_with(pcie_config_file)
assert result == pcie_check_output

@mock.patch('os.path.isfile', mock.MagicMock(return_value=True))
@mock.patch('{}.open'.format(BUILTINS))
def test_get_pcie_aer_stats(self, open_mock):

def open_mock_side_effect(*args):
file_content = ''
if os.path.dirname(args[0]) == pci_sysfs_paths[0]:
file_name = os.path.basename(args[0])
if file_name == 'aer_dev_correctable':
file_content = pcie_aer_correctable_content
elif file_name == 'aer_dev_fatal':
file_content = pcie_aer_fatal_content
elif file_name == 'aer_dev_nonfatal':
file_content = pcie_aer_nonfatal_content

return mock.mock_open(read_data=file_content).return_value

open_mock.side_effect = open_mock_side_effect
pcieutil = PcieUtil(tests_dir)
test_device = pcie_device_list[0]
result = pcieutil.get_pcie_aer_stats(bus=int(test_device['bus']),
dev=int(test_device['dev']),
func=int(test_device['fn']))
assert result == pcie_aer_stats

@mock.patch('sonic_platform_base.sonic_pcie.pcie_common.PcieUtil.get_pcie_device', mock.MagicMock(return_value=pcie_device_list))
def test_dump_conf_yaml(self):
pcieutil = PcieUtil(tests_dir)

# Verify pcie config path before writing to file
open_mock = mock.mock_open()
with mock.patch('{}.open'.format(BUILTINS), open_mock):
pcieutil.dump_conf_yaml()
open_mock.assert_called_once_with(pcie_config_file, 'w')

pcieutil.dump_conf_yaml()
with open(pcie_config_file) as fd:
result = yaml.safe_load(fd)

assert result == pcie_device_list

@classmethod
def teardown_class(cls):
# Cleanup generated config
if os.path.isfile(pcie_config_file):
os.remove(pcie_config_file)

0 comments on commit 9400720

Please sign in to comment.