diff --git a/tests/generic_config_updater/gu_utils.py b/tests/generic_config_updater/gu_utils.py index 75ae171ec71..c6a2b378973 100644 --- a/tests/generic_config_updater/gu_utils.py +++ b/tests/generic_config_updater/gu_utils.py @@ -1,6 +1,7 @@ import json import logging import pytest +from jsonpointer import JsonPointer from tests.common.helpers.assertions import pytest_assert from tests.common.utilities import wait_until from tests.common.config_reload import config_reload @@ -238,3 +239,34 @@ def rollback_or_reload(duthost, cp=DEFAULT_CHECKPOINT_NAME): if output['rc'] or "Config rolled back successfull" not in output['stdout']: config_reload(duthost) pytest.fail("config rollback failed. Restored by config_reload") + +def create_path(tokens): + return JsonPointer.from_parts(tokens).path + +def check_show_ip_intf(duthost, intf_name, expected_content_list, unexpected_content_list, is_ipv4=True): + """Check lo interface status by show command + + Sample output: + admin@vlab-01:~$ show ip interfaces | grep -w Vlan1000 + Vlan1000 192.168.0.1/21 up/up N/A N/A + admin@vlab-01:~$ show ipv6 interfaces | grep -w Vlan1000 + Vlan1000 fc02:1000::1/64 up/up N/A N/A + fe80::5054:ff:feda:c6af%Vlan1000/64 N/A N/A + """ + address_family = "ip" if is_ipv4 else "ipv6" + output = duthost.shell("show {} interfaces | grep -w {} || true".format(address_family, intf_name)) + + expect_res_success(duthost, output, expected_content_list, unexpected_content_list) + +def check_vrf_route_for_intf(duthost, vrf_name, intf_name, is_ipv4=True): + """Check ip route for specific vrf + + Sample output: + admin@vlab-01:~$ show ip route vrf Vrf_01 | grep -w Loopback0 + C>* 10.1.0.32/32 is directly connected, Loopback0, 00:00:13 + """ + address_family = "ip" if is_ipv4 else "ipv6" + output = duthost.shell("show {} route vrf {} | grep -w {}".format(address_family, vrf_name, intf_name)) + + pytest_assert(not output['rc'], + "Route not found for {} in vrf {}".format(intf_name, vrf_name)) diff --git a/tests/generic_config_updater/test_lo_interface.py b/tests/generic_config_updater/test_lo_interface.py index 9eb8287e29c..cbb6c499677 100644 --- a/tests/generic_config_updater/test_lo_interface.py +++ b/tests/generic_config_updater/test_lo_interface.py @@ -2,9 +2,10 @@ 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, expect_res_success +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 +from tests.generic_config_updater.gu_utils import check_show_ip_intf, check_vrf_route_for_intf # Test on t0 topo to verify functionality and to choose predefined variable # "LOOPBACK_INTERFACE": { @@ -42,8 +43,8 @@ def setup_env(duthosts, rand_one_dut_hostname): try: logger.info("Rolled back to original checkpoint") rollback_or_reload(duthost) - check_show_lo_intf(duthost, "Loopback0", ["10.1.0.32/32"], ["Vrf"], ipv4=True) - check_show_lo_intf(duthost, "Loopback0", ["fc00:1::32/128"], ["Vrf"], ipv4=False) + check_show_ip_intf(duthost, "Loopback0", ["10.1.0.32/32"], ["Vrf"], is_ipv4=True) + check_show_ip_intf(duthost, "Loopback0", ["fc00:1::32/128"], ["Vrf"], is_ipv4=False) finally: delete_checkpoint(duthost) @@ -56,21 +57,6 @@ def cleanup_lo_interface_config(duthost, cfg_facts): pytest_assert(not del_loopback_interface['rc'], "Loopback interface '{}' is not deleted successfully".format(lo_interface)) -def check_show_lo_intf(duthost, lo_intf_name, expected_content_list, unexpected_content_list, ipv4=True): - """Check lo interface status by show command - - Sample output: - admin@vlab-01:~$ show ip interfaces | grep Loopback0 - Loopback0 10.1.0.32/32 up/up N/A N/A - admin@vlab-01:~$ show ipv6 interfaces | grep Loopback0 - Loopback0 fc00:1::32/128 up/up N/A N/A - fe80::4a3:18ff:fec2:f9e3%Loopback0/64 N/A N/A - """ - address_family = "ip" if ipv4 else "ipv6" - output = duthost.shell("show {} interfaces | grep {} || true".format(address_family, lo_intf_name)) - - expect_res_success(duthost, output, expected_content_list, unexpected_content_list) - 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 @@ -102,8 +88,8 @@ def test_lo_interface_tc1_add_init(duthost, cfg_facts): output = apply_patch(duthost, json_data=json_patch, dest_file=tmpfile) expect_op_success(duthost, output) - check_show_lo_intf(duthost, "Loopback0", ["10.1.0.32/32"], [], ipv4=True) - check_show_lo_intf(duthost, "Loopback0", ["fc00:1::32/128"], [], ipv4=False) + check_show_ip_intf(duthost, "Loopback0", ["10.1.0.32/32"], [], is_ipv4=True) + check_show_ip_intf(duthost, "Loopback0", ["fc00:1::32/128"], [], is_ipv4=False) finally: delete_tmpfile(duthost, tmpfile) @@ -139,8 +125,8 @@ def test_lo_interface_tc2_add_duplicate(duthost): output = apply_patch(duthost, json_data=json_patch, dest_file=tmpfile) expect_op_success(duthost, output) - check_show_lo_intf(duthost, "Loopback0", ["10.1.0.32/32"], [], ipv4=True) - check_show_lo_intf(duthost, "Loopback0", ["fc00:1::32/128"], [], ipv4=False) + check_show_ip_intf(duthost, "Loopback0", ["10.1.0.32/32"], [], is_ipv4=True) + check_show_ip_intf(duthost, "Loopback0", ["fc00:1::32/128"], [], is_ipv4=False) finally: delete_tmpfile(duthost, tmpfile) @@ -226,8 +212,8 @@ def test_lo_interface_tc4_replace(duthost): output = apply_patch(duthost, json_data=json_patch, dest_file=tmpfile) expect_op_success(duthost, output) - check_show_lo_intf(duthost, "Loopback0", ["10.1.0.33/32"], ["10.1.0.32/32"], ipv4=True) - check_show_lo_intf(duthost, "Loopback0", ["fc00:1::33/128"], ["fc00:1::32/128"], ipv4=False) + check_show_ip_intf(duthost, "Loopback0", ["10.1.0.33/32"], ["10.1.0.32/32"], is_ipv4=True) + check_show_ip_intf(duthost, "Loopback0", ["fc00:1::33/128"], ["fc00:1::32/128"], is_ipv4=False) finally: delete_tmpfile(duthost, tmpfile) @@ -248,24 +234,11 @@ def test_lo_interface_tc5_remove(duthost): output = apply_patch(duthost, json_data=json_patch, dest_file=tmpfile) expect_op_success(duthost, output) - check_show_lo_intf(duthost, "Loopback0", [], ["10.1.0.32/32"], ipv4=True) - check_show_lo_intf(duthost, "Loopback0", [], ["fc00:1::32/128"], ipv4=False) + check_show_ip_intf(duthost, "Loopback0", [], ["10.1.0.32/32"], is_ipv4=True) + check_show_ip_intf(duthost, "Loopback0", [], ["fc00:1::32/128"], is_ipv4=False) finally: delete_tmpfile(duthost, tmpfile) -def check_vrf_route_for_lo_intf(duthost, vrf_name, lo_intf_name, ipv4=True): - """Check ip route for specific vrf - - Sample output: - admin@vlab-01:~$ show ip route vrf Vrf_01 | grep Loopback0 - C>* 10.1.0.32/32 is directly connected, Loopback0, 00:00:13 - """ - address_family = "ip" if ipv4 else "ipv6" - output = duthost.shell("show {} route vrf {} | grep {}".format(address_family, vrf_name, lo_intf_name)) - - pytest_assert(not output['rc'], - "Route not found for {} in vrf {}".format(lo_intf_name, vrf_name)) - def setup_vrf_config(duthost): """Create two vrf and bind Loopback0 to Vrf_01 @@ -300,11 +273,11 @@ def setup_vrf_config(duthost): output = apply_patch(duthost, json_data=json_patch, dest_file=tmpfile) expect_op_success(duthost, output) - check_show_lo_intf(duthost, "Loopback0", ["10.1.0.32/32", "Vrf_01"], [], ipv4=True) - check_show_lo_intf(duthost, "Loopback0", ["fc00:1::32/128", "Vrf_01"], [], ipv4=False) + check_show_ip_intf(duthost, "Loopback0", ["10.1.0.32/32", "Vrf_01"], [], is_ipv4=True) + check_show_ip_intf(duthost, "Loopback0", ["fc00:1::32/128", "Vrf_01"], [], is_ipv4=False) - check_vrf_route_for_lo_intf(duthost, "Vrf_01", "Loopback0", ipv4=True) - check_vrf_route_for_lo_intf(duthost, "Vrf_01", "Loopback0", ipv4=False) + check_vrf_route_for_intf(duthost, "Vrf_01", "Loopback0", is_ipv4=True) + check_vrf_route_for_intf(duthost, "Vrf_01", "Loopback0", is_ipv4=False) finally: delete_tmpfile(duthost, tmpfile) @@ -336,10 +309,10 @@ def test_lo_interface_tc6_vrf_change(duthost): output = apply_patch(duthost, json_data=json_patch, dest_file=tmpfile) expect_op_success(duthost, output) - check_show_lo_intf(duthost, "Loopback0", ["10.1.0.32/32", "Vrf_02"], [], ipv4=True) - check_show_lo_intf(duthost, "Loopback0", ["fc00:1::32/128", "Vrf_02"], [], ipv4=False) + check_show_ip_intf(duthost, "Loopback0", ["10.1.0.32/32", "Vrf_02"], [], is_ipv4=True) + check_show_ip_intf(duthost, "Loopback0", ["fc00:1::32/128", "Vrf_02"], [], is_ipv4=False) - check_vrf_route_for_lo_intf(duthost, "Vrf_02", "Loopback0", ipv4=True) - check_vrf_route_for_lo_intf(duthost, "Vrf_02", "Loopback0", ipv4=False) + check_vrf_route_for_intf(duthost, "Vrf_02", "Loopback0", is_ipv4=True) + check_vrf_route_for_intf(duthost, "Vrf_02", "Loopback0", is_ipv4=False) finally: delete_tmpfile(duthost, tmpfile) diff --git a/tests/generic_config_updater/test_vlan_interface.py b/tests/generic_config_updater/test_vlan_interface.py new file mode 100644 index 00000000000..2a172bfbc92 --- /dev/null +++ b/tests/generic_config_updater/test_vlan_interface.py @@ -0,0 +1,277 @@ +import logging +import pytest + +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 +from tests.generic_config_updater.gu_utils import create_path, check_show_ip_intf + +# Test on t0 topo to verify functionality and to choose predefined variable +# "VLAN_INTERFACE": { +# "Vlan1000": {}, +# "Vlan1000|192.168.0.1/21": {}, +# "Vlan1000|fc02:1000::1/64": {} +# } + +pytestmark = [ + pytest.mark.topology('t0'), +] + +logger = logging.getLogger(__name__) + +@pytest.fixture(autouse=True) +def cleanup_test_env(duthosts, rand_one_dut_hostname): + """ + Setup/teardown fixture for VLAN interface config + 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 + + try: + logger.info("Rolled back to original checkpoint") + rollback_or_reload(duthost) + check_show_ip_intf(duthost, "Vlan1000", ["192.168.0.1/21"], [], is_ipv4=True) + check_show_ip_intf(duthost, "Vlan1000", ["fc02:1000::1/64"], [], is_ipv4=False) + finally: + delete_checkpoint(duthost) + +def test_vlan_interface_tc1_add_duplicate(duthost): + """ Add duplicate v4 and v6 lo intf to config + + Sample output + "VLAN_INTERFACE": { + "Vlan1000": {}, + "Vlan1000|192.168.0.1/21": {}, + "Vlan1000|fc02:1000::1/64": {} + } + """ + json_patch = [ + { + "op": "add", + "path": create_path(["VLAN_INTERFACE", "Vlan1000|192.168.0.1/21"]), + "value": {} + }, + { + "op": "add", + "path": create_path(["VLAN_INTERFACE", "Vlan1000|fc02:1000::1/64"]), + "value": {} + } + ] + + logger.info("json patch {}".format(json_patch)) + + 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) + + check_show_ip_intf(duthost, "Vlan1000", ["192.168.0.1/21"], [], is_ipv4=True) + check_show_ip_intf(duthost, "Vlan1000", ["fc02:1000::1/64"], [], is_ipv4=False) + finally: + delete_tmpfile(duthost, tmpfile) + +@pytest.mark.parametrize("op, name, dummy_vlan_interface_v4, dummy_vlan_interface_v6", [ + ("add", "Vlan1000", "587.168.0.1/21", "fc02:1000::1/64"), + ("add", "Vlan1000", "192.168.0.1/21", "fc02:1000::xyz/64"), + ("remove", "Vlan1000", "192.168.0.2/21", "fc02:1000::1/64"), + ("remove", "Vlan1000", "192.168.0.1/21", "fc02:1000::2/64") +]) +def test_vlan_interface_tc2_xfail(duthost, op, name, + dummy_vlan_interface_v4, dummy_vlan_interface_v6): + """ Test expect fail testcase + + ("add", "Vlan1000", "587.168.0.1/21", "fc02:1000::1/64"), ADD Invalid IPv4 address + ("add", "Vlan1000", "192.168.0.1/21", "fc02:1000::xyz/64"), ADD Invalid IPv6 address + ("remove", "Vlan1000", "192.168.0.2/21", "fc02:1000::1/64"), REMOVE Unexist IPv4 address + ("remove", "Vlan1000", "192.168.0.1/21", "fc02:1000::2/64") REMOVE Unexist IPv6 address + """ + dummy_vlan_interface_v4 = name + "|" + dummy_vlan_interface_v4 + dummy_vlan_interface_v6 = name + "|" + dummy_vlan_interface_v6 + + json_patch = [ + { + "op": "{}".format(op), + "path": create_path(["VLAN_INTERFACE", dummy_vlan_interface_v4]), + "value": {} + } , + { + "op": "{}".format(op), + "path": create_path(["VLAN_INTERFACE", dummy_vlan_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_vlan_interface_tc3_add_new(duthost): + """ Add an brand new vlan interface Vlan2000 + + Sample output: + "VLAN": { + "Vlan1000": { + "dhcp_servers": [ + "192.0.0.1", + "192.0.0.2", + "192.0.0.3", + "192.0.0.4" + ], + "vlanid": "1000" + }, + "Vlan2000": { + "vlanid": "2000" + } + }, + "VLAN_INTERFACE": { + "Vlan1000": {}, + "Vlan2000": {}, + "Vlan1000|192.168.0.1/21": {}, + "Vlan1000|fc02:1000::1/64": {}, + "Vlan2000|192.168.8.1/21": {}, + "Vlan2000|fc02:2000::1/64": {} + } + + admin@vlab-01:~/vlan$ show ip interfaces | grep -w Vlan2000 + Vlan2000 192.168.8.1/21 up/up N/A N/A + admin@vlab-01:~/vlan$ show ipv6 interfaces | grep -w Vlan2000 + Vlan2000 fc02:2000::1/64 up/up N/A N/A + fe80::5054:ff:feda:c6af%Vlan2000/64 N/A N/A + + """ + json_patch = [ + { + "op": "add", + "path": "/VLAN_INTERFACE/Vlan2000", + "value": {} + }, + { + "op": "add", + "path": create_path(["VLAN_INTERFACE", "Vlan2000|192.168.8.1/21"]), + "value": {} + }, + { + "op": "add", + "path": create_path(["VLAN_INTERFACE","Vlan2000|fc02:2000::1/64"]), + "value": {} + }, + { + "op": "add", + "path": "/VLAN/Vlan2000", + "value": { + "vlanid": "2000" + } + } + ] + + 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) + + check_show_ip_intf(duthost, "Vlan2000", ["192.168.8.1/21"], [], is_ipv4=True) + check_show_ip_intf(duthost, "Vlan2000", ["fc02:2000::1/64"], [], is_ipv4=False) + finally: + delete_tmpfile(duthost, tmpfile) + +def test_vlan_interface_tc4_replace(duthost): + """ Test replace testcase + + Expected output + "VLAN_INTERFACE": { + "Vlan1000": {}, + "Vlan1000|192.168.0.2/21": {}, + "Vlan1000|fc02:1000::2/64": {} + } + """ + json_patch = [ + { + "op": "remove", + "path": create_path(["VLAN_INTERFACE", "Vlan1000|fc02:1000::1/64"]), + }, + { + "op": "remove", + "path": create_path(["VLAN_INTERFACE", "Vlan1000|192.168.0.1/21"]), + }, + { + "op": "add", + "path": create_path(["VLAN_INTERFACE", "Vlan1000|192.168.0.2/21"]), + "value": {} + }, + { + "op": "add", + "path": create_path(["VLAN_INTERFACE", "Vlan1000|fc02:1000::2/64"]), + "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) + + check_show_ip_intf(duthost, "Vlan1000", ["192.168.0.2/21"], ["192.168.0.1/21"], is_ipv4=True) + check_show_ip_intf(duthost, "Vlan1000", ["fc02:1000::2/64"], ["fc02:1000::1/64"], is_ipv4=False) + finally: + delete_tmpfile(duthost, tmpfile) + +def test_vlan_interface_tc5_remove(duthost): + """ Remove all VLAN intf + """ + json_patch = [ + { + "op": "remove", + "path": "/VLAN_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) + + check_show_ip_intf(duthost, "Vlan1000", [], ["192.168.0.1/21"], is_ipv4=True) + check_show_ip_intf(duthost, "Vlan1000", [], ["fc02:1000::1/64"], is_ipv4=False) + finally: + delete_tmpfile(duthost, tmpfile) + +def test_vlan_interface_tc6_incremental_change(duthost): + """ Incremental test for VLAN interface + + Note: Current topo doesn't contain those change. + MTU and admin_status incremental change is not support as of 12/10/2021 + """ + json_patch = [ + { + "op": "add", + "path": "/VLAN/Vlan1000/description", + "value": "incremental test for Vlan1000" + } + ] + + 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)