Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add loopback action test cases #5871

Merged
merged 1 commit into from
Feb 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 42 additions & 8 deletions tests/common/devices/sonic.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class SonicHost(AnsibleHostBase):
This type of host contains information about the SONiC device (device info, services, etc.),
and also provides the ability to run Ansible modules on the SONiC device.
"""
DEFAULT_ASIC_SERVICES = ["bgp", "database", "lldp", "swss", "syncd", "teamd"]

def __init__(self, ansible_adhoc, hostname,
shell_user=None, shell_passwd=None,
Expand Down Expand Up @@ -1062,8 +1063,13 @@ def get_ip_route_info(self, dstip, ns=""):
@param dstip: destination. either ip_address or ip_network

Please beware: if dstip is an ip network, you will receive all ECMP nexthops
<<<<<<< HEAD
But if dstip is an ip address, only one nexthop will be returned,
the one which is going to be used to send a packet to the destination.
=======
But if dstip is an ip address, only one nexthop will be returned, the one which is going to be used to
send a packet to the destination.
>>>>>>> 090bc7a72 (Add loopback action test cases)

Exanples:
----------------
Expand All @@ -1076,9 +1082,14 @@ def get_ip_route_info(self, dstip, ns=""):
----------------
get_ip_route_info(ipaddress.ip_network(unicode("192.168.8.0/25")))
returns {'set_src': IPv4Address(u'10.1.0.32'), 'nexthops': [(IPv4Address(u'10.0.0.1'), u'PortChannel0001'),
<<<<<<< HEAD
(IPv4Address(u'10.0.0.5'), u'PortChannel0002'),
(IPv4Address(u'10.0.0.9'), u'PortChannel0003'),
(IPv4Address(u'10.0.0.13'), u'PortChannel0004')]}
=======
(IPv4Address(u'10.0.0.5'), u'PortChannel0002'), (IPv4Address(u'10.0.0.9'), u'PortChannel0003'),
(IPv4Address(u'10.0.0.13'), u'PortChannel0004')]}
>>>>>>> 090bc7a72 (Add loopback action test cases)

raw data
192.168.8.0/25 proto 186 src 10.1.0.32 metric 20
Expand All @@ -1102,9 +1113,14 @@ def get_ip_route_info(self, dstip, ns=""):
----------------
get_ip_route_info(ipaddress.ip_network(unicode("20c0:a818::/64")))
returns {'set_src': IPv6Address(u'fc00:1::32'), 'nexthops': [(IPv6Address(u'fc00::2'), u'PortChannel0001'),
<<<<<<< HEAD
(IPv6Address(u'fc00::a'), u'PortChannel0002'),
(IPv6Address(u'fc00::12'), u'PortChannel0003'),
(IPv6Address(u'fc00::1a'), u'PortChannel0004')]}
=======
(IPv6Address(u'fc00::a'), u'PortChannel0002'), (IPv6Address(u'fc00::12'), u'PortChannel0003'),
(IPv6Address(u'fc00::1a'), u'PortChannel0004')]}
>>>>>>> 090bc7a72 (Add loopback action test cases)

raw data
20c0:a818::/64 via fc00::2 dev PortChannel0001 proto 186 src fc00:1::32 metric 20 pref medium
Expand All @@ -1121,9 +1137,14 @@ def get_ip_route_info(self, dstip, ns=""):
----------------
get_ip_route_info(ipaddress.ip_network(unicode("0.0.0.0/0")))
returns {'set_src': IPv4Address(u'10.1.0.32'), 'nexthops': [(IPv4Address(u'10.0.0.1'), u'PortChannel0001'),
<<<<<<< HEAD
(IPv4Address(u'10.0.0.5'), u'PortChannel0002'),
(IPv4Address(u'10.0.0.9'), u'PortChannel0003'),
(IPv4Address(u'10.0.0.13'), u'PortChannel0004')]}
=======
(IPv4Address(u'10.0.0.5'), u'PortChannel0002'), (IPv4Address(u'10.0.0.9'), u'PortChannel0003'),
(IPv4Address(u'10.0.0.13'), u'PortChannel0004')]}
>>>>>>> 090bc7a72 (Add loopback action test cases)

raw data
default proto 186 src 10.1.0.32 metric 20
Expand All @@ -1140,10 +1161,18 @@ def get_ip_route_info(self, dstip, ns=""):
nexthop via 10.0.0.63 dev PortChannel0004 weight 1
----------------
get_ip_route_info(ipaddress.ip_network(unicode("::/0")))
<<<<<<< HEAD
returns {'set_src': IPv6Address(u'fc00:1::32'), 'nexthops': [(IPv6Address(u'fc00::2'), u'PortChannel0001'),
(IPv6Address(u'fc00::a'), u'PortChannel0002'),
(IPv6Address(u'fc00::12'), u'PortChannel0003'),
(IPv6Address(u'fc00::1a'), u'PortChannel0004')]}
=======
returns {'set_src': IPv6Address(u'fc00:1::32'),
'nexthops': [(IPv6Address(u'fc00::2'), u'PortChannel0001'),
(IPv6Address(u'fc00::a'), u'PortChannel0002'),
(IPv6Address(u'fc00::12'), u'PortChannel0003'),
(IPv6Address(u'fc00::1a'), u'PortChannel0004')]}
>>>>>>> 090bc7a72 (Add loopback action test cases)

raw data
default via fc00::2 dev PortChannel0001 proto 186 src fc00:1::32 metric 20 pref medium
Expand Down Expand Up @@ -1385,8 +1414,8 @@ def _parse_column_positions(self, sep_line, sep_char='-'):
sep_char: The character used in separation line. Defaults to '-'.

Returns:
Returns a list. Each item is a tuple with two elements. The first element is start position of a column. The
second element is the end position of the column.
Returns a list. Each item is a tuple with two elements. The first element is start position of a column.
The second element is the end position of the column.
"""
prev = ' ',
positions = []
Expand All @@ -1401,7 +1430,7 @@ def _parse_column_positions(self, sep_line, sep_char='-'):
prev = char
return positions

def _parse_show(self, output_lines):
def _parse_show(self, output_lines, header_len=1):

result = []

Expand All @@ -1410,7 +1439,7 @@ def _parse_show(self, output_lines):
for idx, line in enumerate(output_lines):
if sep_line_pattern.match(line):
sep_line_found = True
header_line = output_lines[idx-1]
header_lines = output_lines[idx-header_len:idx]
sep_line = output_lines[idx]
content_lines = output_lines[idx+1:]
break
Expand All @@ -1427,7 +1456,8 @@ def _parse_show(self, output_lines):

headers = []
for (left, right) in positions:
headers.append(header_line[left:right].strip().lower())
header = " ".join([header_line[left:right].strip().lower() for header_line in header_lines]).strip()
headers.append(header)

for content_line in content_lines:
# When an empty line is encountered while parsing the tabulate content, it is highly possible that the
Expand All @@ -1443,7 +1473,7 @@ def _parse_show(self, output_lines):

return result

def show_and_parse(self, show_cmd, **kwargs):
def show_and_parse(self, show_cmd, header_len=1, **kwargs):
"""Run a show command and parse the output using a generic pattern.

This method can adapt to the column changes as long as the output format follows the pattern of
Expand Down Expand Up @@ -1481,7 +1511,11 @@ def show_and_parse(self, show_cmd, **kwargs):
"lanes": "4,5,6,7",
"fec": "N/A",
"asym pfc": "off",
"admin": "up", "type": "QSFP+ or later", "vlan": "PortChannel0002", "mtu": "9100", "alias": "etp2",
"admin": "up",
"type": "QSFP+ or later",
"vlan": "PortChannel0002",
"mtu": "9100",
"alias": "etp2",
"interface": "Ethernet4",
"speed": "40G"
},
Expand Down Expand Up @@ -1516,7 +1550,7 @@ def show_and_parse(self, show_cmd, **kwargs):
output = output[start_line_index:]
else:
output = output[start_line_index:end_line_index]
return self._parse_show(output)
return self._parse_show(output, header_len)

@cached(name='mg_facts')
def get_extended_minigraph_facts(self, tbinfo, namespace=DEFAULT_NAMESPACE):
Expand Down
51 changes: 34 additions & 17 deletions tests/common/fixtures/duthost_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ def backup_and_restore_config_db_module(duthosts, rand_one_dut_hostname):
for func in _backup_and_restore_config_db(duthost, "module"):
yield func


@pytest.fixture(scope="package")
def backup_and_restore_config_db_package(duthosts):

for func in _backup_and_restore_config_db(duthosts, "package"):
yield func


@pytest.fixture(scope="session")
def backup_and_restore_config_db_session(duthosts):

Expand Down Expand Up @@ -151,21 +159,20 @@ def disable_fdb_aging(duthost):
duthost.shell_cmds(cmds=cmds)
duthost.file(path=TMP_SWITCH_CONFIG_FILE, state="absent")


@pytest.fixture(scope="module")
def ports_list(duthosts, rand_one_dut_hostname, rand_selected_dut, tbinfo):
duthost = duthosts[rand_one_dut_hostname]
cfg_facts = duthost.config_facts(host=duthost.hostname, source="persistent")['ansible_facts']
mg_facts = rand_selected_dut.get_extended_minigraph_facts(tbinfo)
config_ports = {k: v for k,v in cfg_facts['PORT'].items() if v.get('admin_status', 'down') == 'up'}
config_ports = {k: v for k, v in cfg_facts['PORT'].items() if v.get('admin_status', 'down') == 'up'}
config_port_indices = {k: v for k, v in mg_facts['minigraph_ptf_indices'].items() if k in config_ports}
ptf_ports_available_in_topo = {port_index: 'eth{}'.format(port_index) for port_index in config_port_indices.values()}
config_portchannels = cfg_facts.get('PORTCHANNEL', {})
config_port_channel_members = [port_channel['members'] for port_channel in config_portchannels.values()]
config_port_channel_member_ports = list(itertools.chain.from_iterable(config_port_channel_members))
ports = [port for port in config_ports
if config_port_indices[port] in ptf_ports_available_in_topo
and config_ports[port].get('admin_status', 'down') == 'up'
and port not in config_port_channel_member_ports]
ports = [port for port in config_ports if config_port_indices[port] in ptf_ports_available_in_topo and
config_ports[port].get('admin_status', 'down') == 'up' and port not in config_port_channel_member_ports]
return ports


Expand All @@ -182,7 +189,7 @@ def check_orch_cpu_utilization(dut, orch_cpu_threshold):
orch_cpu = dut.shell("COLUMNS=512 show processes cpu | grep orchagent | awk '{print $9}'")["stdout_lines"]
for line in orch_cpu:
if int(float(line)) > orch_cpu_threshold:
return False
return False
time.sleep(1)
return True

Expand All @@ -191,12 +198,15 @@ def check_ebgp_routes(num_v4_routes, num_v6_routes, duthost):
MAX_DIFF = 5
sumv4, sumv6 = duthost.get_ip_route_summary()
rtn_val = True
if 'ebgp' in sumv4 and 'routes' in sumv4['ebgp'] and abs(int(float(sumv4['ebgp']['routes'])) - int(float(num_v4_routes))) >= MAX_DIFF:
if 'ebgp' in sumv4 and 'routes' in sumv4['ebgp'] and \
abs(int(float(sumv4['ebgp']['routes'])) - int(float(num_v4_routes))) >= MAX_DIFF:
rtn_val = False
if 'ebgp' in sumv6 and 'routes' in sumv6['ebgp'] and abs(int(float(sumv6['ebgp']['routes'])) - int(float(num_v6_routes))) >= MAX_DIFF:
if 'ebgp' in sumv6 and 'routes' in sumv6['ebgp'] and \
abs(int(float(sumv6['ebgp']['routes'])) - int(float(num_v6_routes))) >= MAX_DIFF:
rtn_val = False
return rtn_val


@pytest.fixture(scope="module")
def shutdown_ebgp(duthosts):
# To store the original number of eBGP v4 and v6 routes.
Expand Down Expand Up @@ -229,11 +239,14 @@ def shutdown_ebgp(duthosts):
orig_v4_ebgp = v4ebgps[duthost.hostname]
orig_v6_ebgp = v6ebgps[duthost.hostname]
pytest_assert(wait_until(120, 10, 10, check_ebgp_routes, orig_v4_ebgp, orig_v6_ebgp, duthost),
"eBGP v4 routes are {}, and v6 route are {}, and not what they were originally after enabling all neighbors on {}".format(orig_v4_ebgp, orig_v6_ebgp, duthost))
"eBGP v4 routes are {}, and v6 route are {}, and not what they were originally after enabling "
"all neighbors on {}".format(orig_v4_ebgp, orig_v6_ebgp, duthost))
pytest_assert(wait_until(60, 2, 0, check_orch_cpu_utilization, duthost, orch_cpu_threshold),
"Orch CPU utilization {} > orch cpu threshold {} after startup all eBGP"
.format(duthost.shell("show processes cpu | grep orchagent | awk '{print $9}'")["stdout"],
orch_cpu_threshold))


@pytest.fixture(scope="module")
def utils_vlan_ports_list(duthosts, rand_one_dut_hostname, rand_selected_dut, tbinfo, ports_list):
"""
Expand All @@ -243,7 +256,7 @@ def utils_vlan_ports_list(duthosts, rand_one_dut_hostname, rand_selected_dut, tb
cfg_facts = duthost.config_facts(host=duthost.hostname, source="persistent")['ansible_facts']
mg_facts = rand_selected_dut.get_extended_minigraph_facts(tbinfo)
vlan_ports_list = []
config_ports = {k: v for k,v in cfg_facts['PORT'].items() if v.get('admin_status', 'down') == 'up'}
config_ports = {k: v for k, v in cfg_facts['PORT'].items() if v.get('admin_status', 'down') == 'up'}
config_portchannels = cfg_facts.get('PORTCHANNEL', {})
config_port_indices = {k: v for k, v in mg_facts['minigraph_ptf_indices'].items() if k in config_ports}
config_ports_vlan = collections.defaultdict(list)
Expand All @@ -264,14 +277,14 @@ def utils_vlan_ports_list(duthosts, rand_one_dut_hostname, rand_selected_dut, tb
if 'tagging_mode' not in vlan_members[k][port]:
continue
mode = vlan_members[k][port]['tagging_mode']
config_ports_vlan[port].append({'vlanid':int(vlanid), 'ip':ip, 'tagging_mode':mode})
config_ports_vlan[port].append({'vlanid':int(vlanid), 'ip': ip, 'tagging_mode': mode})

if config_portchannels:
for po in config_portchannels:
vlan_port = {
'dev' : po,
'port_index' : [config_port_indices[member] for member in config_portchannels[po]['members']],
'permit_vlanid' : []
'dev': po,
'port_index': [config_port_indices[member] for member in config_portchannels[po]['members']],
'permit_vlanid': []
}
if po in config_ports_vlan:
vlan_port['pvid'] = 0
Expand All @@ -286,9 +299,9 @@ def utils_vlan_ports_list(duthosts, rand_one_dut_hostname, rand_selected_dut, tb

for i, port in enumerate(ports_list):
vlan_port = {
'dev' : port,
'port_index' : [config_port_indices[port]],
'permit_vlanid' : []
'dev': port,
'port_index': [config_port_indices[port]],
'permit_vlanid': []
}
if port in config_ports_vlan:
vlan_port['pvid'] = 0
Expand All @@ -303,11 +316,13 @@ def utils_vlan_ports_list(duthosts, rand_one_dut_hostname, rand_selected_dut, tb

return vlan_ports_list


def compare_network(src_ipprefix, dst_ipprefix):
src_network = ipaddress.IPv4Interface(src_ipprefix).network
dst_network = ipaddress.IPv4Interface(dst_ipprefix).network
return src_network.overlaps(dst_network)


@pytest.fixture(scope="module")
def utils_vlan_intfs_dict_orig(duthosts, rand_one_dut_hostname, tbinfo):
'''A module level fixture to record duthost's original vlan info
Expand Down Expand Up @@ -343,6 +358,7 @@ def utils_vlan_intfs_dict_orig(duthosts, rand_one_dut_hostname, tbinfo):
vlan_intfs_dict[int(vlanid)] = {'ip': ip, 'orig': True}
return vlan_intfs_dict


def utils_vlan_intfs_dict_add(vlan_intfs_dict, add_cnt):
'''Utilities function to add add_cnt of new VLAN

Expand Down Expand Up @@ -377,6 +393,7 @@ def utils_vlan_intfs_dict_add(vlan_intfs_dict, add_cnt):
assert vlan_cnt == add_cnt
return vlan_intfs_dict


def utils_create_test_vlans(duthost, cfg_facts, vlan_ports_list, vlan_intfs_dict, delete_untagged_vlan):
'''Utilities function to create vlans for test

Expand Down
Empty file.
8 changes: 8 additions & 0 deletions tests/common/plugins/allure_wrapper/allure_step_wrapper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import logging
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well done, we should start using it for any new test, please inform the team

Copy link
Contributor Author

@nhe-NV nhe-NV Jul 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All in all looking good, Nana. Please review the minor comments. What is the test runtime?

It takes around 15 mins to finish all the test cases

from allure_commons._allure import step as raw_allure_step
logger = logging.getLogger(__name__)


def step(title):
logger.info("Allure step: {}".format(title))
return raw_allure_step(title)
Empty file.
Loading