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

GCU loopback interface test #4814

Merged
merged 7 commits into from
Dec 22, 2021
Merged
Show file tree
Hide file tree
Changes from 4 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
68 changes: 66 additions & 2 deletions tests/generic_config_updater/gu_utils.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import json
import logging
import pytest
from tests.common.helpers.assertions import pytest_assert
from tests.common.utilities import wait_until

from tests.common.config_reload import config_reload

logger = logging.getLogger(__name__)

CONTAINER_SERVICES_LIST = ["swss", "syncd", "radv", "lldp", "dhcp_relay", "teamd", "bgp", "pmon", "telemetry", "acms"]
DEFAULT_CHECKPOINT_NAME = "test"
DEFAULT_ROLLBACK_NAME = DEFAULT_CHECKPOINT_NAME
YANG_IGNORED_OPTIONS = "-i /FEATURE -i /QUEUE -i /SCHEDULER"
ghooo marked this conversation as resolved.
Show resolved Hide resolved

def generate_tmpfile(duthost):
"""Generate temp file
Expand All @@ -28,7 +32,7 @@ def apply_patch(duthost, json_data, dest_file):
"""
duthost.copy(content=json.dumps(json_data, indent=4), dest=dest_file)

cmds = 'config apply-patch {}'.format(dest_file)
cmds = 'config apply-patch {} {}'.format(YANG_IGNORED_OPTIONS, dest_file)

logger.info("Commands: {}".format(cmds))
output = duthost.shell(cmds, module_ignore_errors=True)
Expand Down Expand Up @@ -143,3 +147,63 @@ def reset_start_limit_hit(duthost, service_name, timeout, interval, delay):
reset_service,
"Failed to reset service '{}' due to start-limit-hit".format(service_name)
)

def create_checkpoint(duthost, cp=DEFAULT_CHECKPOINT_NAME):
"""Run checkpoint on target duthost

Args:
duthost: Device Under Test (DUT)
cp: checkpoint filename
"""
cmds = 'config checkpoint {}'.format(cp)

logger.info("Commands: {}".format(cmds))
output = duthost.shell(cmds, module_ignore_errors=True)

pytest_assert(
not output['rc'] and "Checkpoint created successfully" in output['stdout'],
"Failed to config a checkpoint file: {}".format(cp)
)

def delete_checkpoint(duthost, cp=DEFAULT_CHECKPOINT_NAME):
"""Run checkpoint on target duthost

Args:
duthost: Device Under Test (DUT)
cp: checkpoint filename
"""
cmds = 'config delete-checkpoint {}'.format(cp)

logger.info("Commands: {}".format(cmds))
output = duthost.shell(cmds, module_ignore_errors=True)

pytest_assert(
not output['rc'] and "Checkpoint deleted successfully" in output['stdout'],
"Failed to delete a checkpoint file: {}".format(cp)
)

def rollback(duthost, rb=DEFAULT_ROLLBACK_NAME):
wen587 marked this conversation as resolved.
Show resolved Hide resolved
"""Run rollback on target duthost

Args:
duthost: Device Under Test (DUT)
rb: rollback filename
"""
cmds = 'config rollback {} {}'.format(YANG_IGNORED_OPTIONS, rb)

logger.info("Commands: {}".format(cmds))
output = duthost.shell(cmds, module_ignore_errors=True)

return output

def rollback_or_reload(duthost):
wen587 marked this conversation as resolved.
Show resolved Hide resolved
"""Run rollback on target duthost. config_reload if rollback failed.

Args:
duthost: Device Under Test (DUT)
"""
output = rollback(duthost)

if output['rc'] or "Config rolled back successfull" not in output['stdout']:
config_reload(duthost)
isabelmsft marked this conversation as resolved.
Show resolved Hide resolved
pytest.fail("config rollback failed. Restored by config_reload")
211 changes: 211 additions & 0 deletions tests/generic_config_updater/test_lo_interface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
import logging
import pytest

from tests.common.helpers.assertions import pytest_assert
from tests.generic_config_updater.gu_utils import apply_patch, expect_op_success, expect_op_failure
from tests.generic_config_updater.gu_utils import generate_tmpfile, delete_tmpfile
from tests.generic_config_updater.gu_utils import create_checkpoint, delete_checkpoint, rollback_or_reload

# Test on t0 topo to verify functionality and to choose predefined variable
# "LOOPBACK_INTERFACE": {
# "Loopback0": {},
# "Loopback0|10.1.0.32/32": {},
# "Loopback0|FC00:1::32/128": {}
# }
pytestmark = [
pytest.mark.topology('t0'),
]

logger = logging.getLogger(__name__)

@pytest.fixture(autouse=True)
def setup_env(duthosts, rand_one_dut_hostname):
"""
Setup/teardown fixture for each loopback interface test
Args:
duthosts: list of DUTs.
rand_selected_dut: The fixture returns a randomly selected DuT.
"""
duthost = duthosts[rand_one_dut_hostname]
create_checkpoint(duthost)

yield
ghooo marked this conversation as resolved.
Show resolved Hide resolved

try:
logger.info("Rolled back to original checkpoint")
isabelmsft marked this conversation as resolved.
Show resolved Hide resolved
rollback_or_reload(duthost)
finally:
delete_checkpoint(duthost)

# Cleanup LOOPBACK_INTERFACE config
def cleanup_lo_interface_config(duthost, cfg_facts):
lo_interfaces = cfg_facts.get('LOOPBACK_INTERFACE', {})
for lo_interface in lo_interfaces:
del_loopback_interface = duthost.shell("sudo config loopback del {}".format(lo_interface),
module_ignore_errors=True)
pytest_assert(not del_loopback_interface['rc'],
"Loopback interface '{}' is not deleted successfully".format(lo_interface))

def test_lo_interface_tc1_add_init(duthost, cfg_facts):
""" Clean up orig lo interface and test initial addion of v4 and v6 lo intf

Expected output
"LOOPBACK_INTERFACE": {
"Loopback0": {},
"Loopback0|10.1.0.32/32": {},
"Loopback0|FC00:1::32/128": {}
}
"""
cleanup_lo_interface_config(duthost, cfg_facts)

json_patch = [
{
"op": "add",
"path": "/LOOPBACK_INTERFACE",
"value": {
"Loopback0": {},
"Loopback0|10.1.0.32/32": {},
"Loopback0|FC00:1::32/128": {}
}
}
]

tmpfile = generate_tmpfile(duthost)
logger.info("tmpfile {}".format(tmpfile))

try:
output = apply_patch(duthost, json_data=json_patch, dest_file=tmpfile)
expect_op_success(duthost, output)
ghooo marked this conversation as resolved.
Show resolved Hide resolved
finally:
delete_tmpfile(duthost, tmpfile)

def test_lo_interface_tc2_add_duplicate(duthost):
""" Add v4 and v6 duplicate lo intf to config

Note: the Identifier '/' as changed to '~1'
Initial Loopback setup in t0
"LOOPBACK_INTERFACE": {
"Loopback0": {},
"Loopback0|10.1.0.32/32": {},
"Loopback0|FC00:1::32/128": {}
}
"""
json_patch = [
{
"op": "add",
"path": "/LOOPBACK_INTERFACE/Loopback0|10.1.0.32~132",
ghooo marked this conversation as resolved.
Show resolved Hide resolved
"value": {}
},
{
"op": "add",
"path": "/LOOPBACK_INTERFACE/Loopback0|FC00:1::32~1128",
"value": {}
}
]

tmpfile = generate_tmpfile(duthost)
logger.info("tmpfile {}".format(tmpfile))

try:
output = apply_patch(duthost, json_data=json_patch, dest_file=tmpfile)
expect_op_success(duthost, output)
finally:
delete_tmpfile(duthost, tmpfile)

@pytest.mark.parametrize("op, name, dummy_lo_interface_v4, dummy_lo_interface_v6", [
("add", "Loopback0", "587.1.0.32~132", "FC00:1::32~1128"),
("add", "Loopback0", "10.1.0.32~132", "FC00:1::xyz~1128"),
("remove", "Loopback0", "10.1.0.33~132", "FC00:1::32~1128"),
("remove", "Loopback0", "10.1.0.32~132", "FC00:1::33~1128")
])
def test_lo_interface_tc3_xfail(duthost, op, name,
dummy_lo_interface_v4, dummy_lo_interface_v6):
""" Test expect fail testcase

("add", "Loopback0", "587.1.0.32~132", "FC00:1::32~1128"), ADD Invalid IPv4 address
("add", "Loopback0", "10.1.0.32~132", "FC00:1::xyz~1128"), ADD Invalid IPv6 address
("remove", "Loopback0", "10.1.0.33~132", "FC00:1::32~1128"), REMOVE Unexist IPv4 address
("remove", "Loopback0", "10.1.0.32~132", "FC00:1::33~1128") REMOVE Unexist IPv6 address
"""
dummy_lo_interface_v4 = name + "|" + dummy_lo_interface_v4
dummy_lo_interface_v6 = name + "|" + dummy_lo_interface_v6

json_patch = [
{
"op": "{}".format(op),
"path": "/LOOPBACK_INTERFACE/{}".format(dummy_lo_interface_v4),
"value": {}
},
{
"op": "{}".format(op),
"path": "/LOOPBACK_INTERFACE/{}".format(dummy_lo_interface_v6),
"value": {}
}
]

tmpfile = generate_tmpfile(duthost)
logger.info("tmpfile {}".format(tmpfile))

try:
output = apply_patch(duthost, json_data=json_patch, dest_file=tmpfile)
expect_op_failure(output)
finally:
delete_tmpfile(duthost, tmpfile)

def test_lo_interface_tc4_replace(duthost):
""" Replace v4 and v6 loopback intf ip
Expected output
"LOOPBACK_INTERFACE": {
"Loopback0": {},
"Loopback0|10.1.0.33/32": {},
"Loopback0|FC00:1::33/128": {}
}
"""
json_patch = [
{
"op": "remove",
"path": "/LOOPBACK_INTERFACE/Loopback0|FC00:1::32~1128"
},
{
"op": "remove",
"path": "/LOOPBACK_INTERFACE/Loopback0|10.1.0.32~132"
},
{
"op": "add",
"path": "/LOOPBACK_INTERFACE/Loopback0|10.1.0.33~132",
"value": {}
},
{
"op": "add",
"path": "/LOOPBACK_INTERFACE/Loopback0|FC00:1::33~1128",
"value": {}
}
]

tmpfile = generate_tmpfile(duthost)
logger.info("tmpfile {}".format(tmpfile))

try:
output = apply_patch(duthost, json_data=json_patch, dest_file=tmpfile)
expect_op_success(duthost, output)
finally:
delete_tmpfile(duthost, tmpfile)

def test_lo_interface_tc5_remove(duthost):
""" Remove v4 and v6 loopback intf config
"""
json_patch = [
{
"op": "remove",
"path": "/LOOPBACK_INTERFACE"
}
]

tmpfile = generate_tmpfile(duthost)
logger.info("tmpfile {}".format(tmpfile))

try:
output = apply_patch(duthost, json_data=json_patch, dest_file=tmpfile)
expect_op_success(duthost, output)
finally:
delete_tmpfile(duthost, tmpfile)