From f9c2905e02d033e10a9f0fa97185bd9b19ed8061 Mon Sep 17 00:00:00 2001 From: karavasi Date: Wed, 23 Oct 2024 18:42:22 +0200 Subject: [PATCH 1/4] Common changes for adding GCU MA/T2 support --- tests/common/gu_utils.py | 53 +++++++++++++++++++ .../tests_mark_conditions.yaml | 4 +- tests/conftest.py | 36 ++++++++++++- tests/generic_config_updater/conftest.py | 15 +++--- 4 files changed, 96 insertions(+), 12 deletions(-) diff --git a/tests/common/gu_utils.py b/tests/common/gu_utils.py index 3bf7da0d5bf..a138efb239e 100644 --- a/tests/common/gu_utils.py +++ b/tests/common/gu_utils.py @@ -42,6 +42,9 @@ def apply_patch(duthost, json_data, dest_file): dest_file: Destination file on duthost """ duthost.copy(content=json.dumps(json_data, indent=4), dest=dest_file) + patch_content = json.dumps(json_data, indent=4) + duthost.copy(content=patch_content, dest=dest_file) + logger.debug("Patch Content: {}".format(patch_content)) cmds = 'config apply-patch {}'.format(dest_file) @@ -477,3 +480,53 @@ def expect_acl_rule_removed(duthost, rulename, setup): removed = len(output) == 0 pytest_assert(removed, "'{}' showed a rule, this following rule should have been removed".format(cmds)) + + +def save_backup_test_config(duthost, file_postfix="bkp"): + """Save test env before a test case starts. + Back up the existing config_db.json file(s). + Args: + duthost: Device Under Test (DUT) + file_postfix: Postfix string to be used for the backup files. + Returns: + None. + """ + CONFIG_DB = "/etc/sonic/config_db.json" + CONFIG_DB_BACKUP = "/etc/sonic/config_db.json.{}".format(file_postfix) + + logger.info("Backup {} to {} on {}".format( + CONFIG_DB, CONFIG_DB_BACKUP, duthost.hostname)) + duthost.shell("cp {} {}".format(CONFIG_DB, CONFIG_DB_BACKUP)) + if duthost.is_multi_asic: + for n in range(len(duthost.asics)): + asic_config_db = "/etc/sonic/config_db{}.json".format(n) + asic_config_db_backup = "/etc/sonic/config_db{}.json.{}".format(n, file_postfix) + logger.info("Backup {} to {} on {}".format( + asic_config_db, asic_config_db_backup, duthost.hostname)) + duthost.shell("cp {} {}".format(asic_config_db, asic_config_db_backup)) + + +def restore_backup_test_config(duthost, file_postfix="bkp", config_reload=True): + """Restore test env after a test case finishes. + Args: + duthost: Device Under Test (DUT) + file_postfix: Postfix string to be used for restoring the saved backup files. + Returns: + None. + """ + CONFIG_DB = "/etc/sonic/config_db.json" + CONFIG_DB_BACKUP = "/etc/sonic/config_db.json.{}".format(file_postfix) + + logger.info("Restore {} with {} on {}".format( + CONFIG_DB, CONFIG_DB_BACKUP, duthost.hostname)) + duthost.shell("mv {} {}".format(CONFIG_DB_BACKUP, CONFIG_DB)) + if duthost.is_multi_asic: + for n in range(len(duthost.asics)): + asic_config_db = "/etc/sonic/config_db{}.json".format(n) + asic_config_db_backup = "/etc/sonic/config_db{}.json.{}".format(n, file_postfix) + logger.info("Restore {} with {} on {}".format( + asic_config_db, asic_config_db_backup, duthost.hostname)) + duthost.shell("mv {} {}".format(asic_config_db_backup, asic_config_db)) + + if config_reload: + config_reload(duthost) diff --git a/tests/common/plugins/conditional_mark/tests_mark_conditions.yaml b/tests/common/plugins/conditional_mark/tests_mark_conditions.yaml index 0bac7ac4313..2b38889581b 100644 --- a/tests/common/plugins/conditional_mark/tests_mark_conditions.yaml +++ b/tests/common/plugins/conditional_mark/tests_mark_conditions.yaml @@ -751,9 +751,9 @@ fib/test_fib.py::test_ipinip_hash: ####################################### generic_config_updater: skip: - reason: 'generic_config_updater is not a supported feature for T2' + reason: 'generic_config_updater is not a supported feature for T2 platform on older releases than 202205.' conditions: - - "'t2' in topo_name" + - "('t2' in topo_name) and (release in ['201811', '201911', '202012', '202106', '202111'])" generic_config_updater/test_dhcp_relay.py: skip: diff --git a/tests/conftest.py b/tests/conftest.py index b5bc8d21e6f..2cbe39e1fb4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -577,6 +577,40 @@ def rand_one_dut_lossless_prio(request): return lossless_prio_list[0] +@pytest.fixture(scope="module") +def rand_asic_namespace(duthosts, rand_one_dut_hostname): + """ + Return the randomly selected asic namespace in case of multi-asic duthost. + """ + duthost = duthosts[rand_one_dut_hostname] + + asic_namespace = None + asic_index = None + if duthost.is_multi_asic: + namespace_list = duthost.get_asic_namespace_list() + asic_namespace = random.choice(namespace_list) + asic_index = duthost.get_asic_id_from_namespace(asic_namespace) + + return asic_namespace, asic_index + + +@pytest.fixture(scope="module") +def rand_front_end_asic_namespace(duthosts, rand_one_dut_front_end_hostname): + """ + Return the randomly selected asic namespace in case of multi-asic frontend duthost. + """ + duthost = duthosts[rand_one_dut_front_end_hostname] + + asic_namespace = None + asic_index = None + if duthost.is_multi_asic: + namespace_list = duthost.get_asic_namespace_list() + asic_namespace = random.choice(namespace_list) + asic_index = duthost.get_asic_id_from_namespace(asic_namespace) + + return asic_namespace, asic_index + + @pytest.fixture(scope="module", autouse=True) def reset_critical_services_list(duthosts): """ @@ -2070,7 +2104,7 @@ def dut_test_params_qos(duthosts, tbinfo, ptfhost, get_src_dst_asic_and_duts, lo yield rtn_dict -@ pytest.fixture(scope='class') +@pytest.fixture(scope='class') def dut_test_params(duthosts, enum_rand_one_per_hwsku_frontend_hostname, tbinfo, ptf_portmap_file, lower_tor_host, creds): # noqa F811 """ diff --git a/tests/generic_config_updater/conftest.py b/tests/generic_config_updater/conftest.py index 6e14fd1374e..83086ff84b3 100644 --- a/tests/generic_config_updater/conftest.py +++ b/tests/generic_config_updater/conftest.py @@ -3,7 +3,7 @@ from tests.common.utilities import skip_release from tests.common.config_reload import config_reload -from tests.common.gu_utils import apply_patch +from tests.common.gu_utils import apply_patch, restore_backup_test_config, save_backup_test_config from tests.common.gu_utils import generate_tmpfile, delete_tmpfile CONFIG_DB = "/etc/sonic/config_db.json" @@ -14,7 +14,7 @@ # Module Fixture @pytest.fixture(scope="module") -def cfg_facts(duthosts, rand_one_dut_hostname): +def cfg_facts(duthosts, rand_one_dut_hostname, rand_asic_namespace): """ Config facts for selected DUT Args: @@ -22,7 +22,8 @@ def cfg_facts(duthosts, rand_one_dut_hostname): rand_one_dut_hostname: Hostname of a random chosen dut """ duthost = duthosts[rand_one_dut_hostname] - return duthost.config_facts(host=duthost.hostname, source="persistent")['ansible_facts'] + asic_namespace, asic_id = rand_asic_namespace + return duthost.config_facts(host=duthost.hostname, source="persistent", namespace=asic_namespace)['ansible_facts'] @pytest.fixture(scope="module", autouse=True) @@ -62,9 +63,7 @@ def reset_and_restore_test_environment(duthosts, rand_one_dut_hostname): finally: delete_tmpfile(duthost, tmpfile) - logger.info("Backup {} to {} on {}".format( - CONFIG_DB, CONFIG_DB_BACKUP, duthost.hostname)) - duthost.shell("cp {} {}".format(CONFIG_DB, CONFIG_DB_BACKUP)) + save_backup_test_config(duthost, file_postfix="before_gcu_test") if output['rc'] or "Patch applied successfully" not in output['stdout']: logger.info("Running config failed SONiC Yang validation. Reload minigraph. config: {}" @@ -73,9 +72,7 @@ def reset_and_restore_test_environment(duthosts, rand_one_dut_hostname): yield - logger.info("Restore {} with {} on {}".format( - CONFIG_DB, CONFIG_DB_BACKUP, duthost.hostname)) - duthost.shell("mv {} {}".format(CONFIG_DB_BACKUP, CONFIG_DB)) + restore_backup_test_config(duthost, file_postfix="before_gcu_test", config_reload=False) if output['rc'] or "Patch applied successfully" not in output['stdout']: logger.info("Restore Config after GCU test.") From 2947290d0b01efd47a64db04e091245a39157489 Mon Sep 17 00:00:00 2001 From: karavasi Date: Thu, 31 Oct 2024 13:08:53 +0100 Subject: [PATCH 2/4] Adding an intermediate fixture to support generic_config_updater module setup, compatible with both frontend and any type of DUT host test suites. --- tests/generic_config_updater/conftest.py | 42 +++++++++++++++--------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/tests/generic_config_updater/conftest.py b/tests/generic_config_updater/conftest.py index 83086ff84b3..e76ad4d47bf 100644 --- a/tests/generic_config_updater/conftest.py +++ b/tests/generic_config_updater/conftest.py @@ -12,49 +12,61 @@ logger = logging.getLogger(__name__) +@pytest.fixture(scope="module") +def selected_dut_hostname(request, rand_one_dut_hostname): + """Fixture that returns either `rand_one_dut_hostname` or `rand_one_dut_front_end_hostname` + depending on availability.""" + if "rand_one_dut_front_end_hostname" in request.fixturenames: + logger.info("Running on front end duthost") + return request.getfixturevalue("rand_one_dut_front_end_hostname") + else: + logger.info("Running on any type of duthost") + return rand_one_dut_hostname + + # Module Fixture @pytest.fixture(scope="module") -def cfg_facts(duthosts, rand_one_dut_hostname, rand_asic_namespace): +def cfg_facts(duthosts, selected_dut_hostname, rand_asic_namespace): """ Config facts for selected DUT Args: duthosts: list of DUTs. - rand_one_dut_hostname: Hostname of a random chosen dut + selected_dut_hostname: Hostname of a random chosen dut """ - duthost = duthosts[rand_one_dut_hostname] + duthost = duthosts[selected_dut_hostname] asic_namespace, asic_id = rand_asic_namespace return duthost.config_facts(host=duthost.hostname, source="persistent", namespace=asic_namespace)['ansible_facts'] @pytest.fixture(scope="module", autouse=True) -def check_image_version(duthosts, rand_one_dut_hostname): +def check_image_version(duthosts, selected_dut_hostname): """Skips this test if the SONiC image installed on DUT is older than 202111 Args: duthosts: list of DUTs. - rand_one_dut_hostname: Hostname of a random chosen dut + selected_dut_hostname: Hostname of a random chosen dut Returns: None. """ - duthost = duthosts[rand_one_dut_hostname] + duthost = duthosts[selected_dut_hostname] skip_release(duthost, ["201811", "201911", "202012", "202106", "202111"]) @pytest.fixture(scope="module", autouse=True) -def reset_and_restore_test_environment(duthosts, rand_one_dut_hostname): +def reset_and_restore_test_environment(duthosts, selected_dut_hostname): """Reset and restore test env if initial Config cannot pass Yang Back up the existing config_db.json file and restore it once the test ends. Args: duthosts: list of DUTs. - rand_one_dut_hostname: Hostname of a random chosen dut + selected_dut_hostname: Hostname of a random chosen dut Returns: None. """ - duthost = duthosts[rand_one_dut_hostname] + duthost = duthosts[selected_dut_hostname] json_patch = [] tmpfile = generate_tmpfile(duthost) @@ -80,17 +92,17 @@ def reset_and_restore_test_environment(duthosts, rand_one_dut_hostname): @pytest.fixture(scope="module", autouse=True) -def verify_configdb_with_empty_input(duthosts, rand_one_dut_hostname): +def verify_configdb_with_empty_input(duthosts, selected_dut_hostname): """Fail immediately if empty input test failure Args: duthosts: list of DUTs. - rand_one_dut_hostname: Hostname of a random chosen dut + selected_dut_hostname: Hostname of a random chosen dut Returns: None. """ - duthost = duthosts[rand_one_dut_hostname] + duthost = duthosts[selected_dut_hostname] json_patch = [] tmpfile = generate_tmpfile(duthost) @@ -116,7 +128,7 @@ def skip_when_buffer_is_dynamic_model(duthost): # Function Fixture @pytest.fixture(autouse=True) -def ignore_expected_loganalyzer_exceptions(duthosts, rand_one_dut_hostname, loganalyzer): +def ignore_expected_loganalyzer_exceptions(duthosts, selected_dut_hostname, loganalyzer): """ Ignore expected yang validation failure during test execution @@ -124,11 +136,11 @@ def ignore_expected_loganalyzer_exceptions(duthosts, rand_one_dut_hostname, loga Args: duthosts: list of DUTs. - rand_one_dut_hostname: Hostname of a random chosen dut + selected_dut_hostname: Hostname of a random chosen dut loganalyzer: Loganalyzer utility fixture """ # When loganalyzer is disabled, the object could be None - duthost = duthosts[rand_one_dut_hostname] + duthost = duthosts[selected_dut_hostname] if loganalyzer: ignoreRegex = [ ".*ERR sonic_yang.*", From 77aaf0cc1d859adc092d61ee7644a5b6bc93cd8e Mon Sep 17 00:00:00 2001 From: karavasi Date: Wed, 13 Nov 2024 17:54:41 +0100 Subject: [PATCH 3/4] Removing duplicated copy --- tests/common/gu_utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/common/gu_utils.py b/tests/common/gu_utils.py index a138efb239e..0c32e8d4e10 100644 --- a/tests/common/gu_utils.py +++ b/tests/common/gu_utils.py @@ -41,7 +41,6 @@ def apply_patch(duthost, json_data, dest_file): json_data: Source json patch to apply dest_file: Destination file on duthost """ - duthost.copy(content=json.dumps(json_data, indent=4), dest=dest_file) patch_content = json.dumps(json_data, indent=4) duthost.copy(content=patch_content, dest=dest_file) logger.debug("Patch Content: {}".format(patch_content)) From c311296edb6f921a75eaf36fb2747b962e1ef5f0 Mon Sep 17 00:00:00 2001 From: karavasi Date: Thu, 28 Nov 2024 14:44:06 +0100 Subject: [PATCH 4/4] Combining two new fixtures to a common --- tests/conftest.py | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 6c42271b7be..134da63177b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -578,28 +578,17 @@ def rand_one_dut_lossless_prio(request): @pytest.fixture(scope="module") -def rand_asic_namespace(duthosts, rand_one_dut_hostname): +def rand_asic_namespace(request, duthosts, rand_one_dut_hostname): """ Return the randomly selected asic namespace in case of multi-asic duthost. """ - duthost = duthosts[rand_one_dut_hostname] - - asic_namespace = None - asic_index = None - if duthost.is_multi_asic: - namespace_list = duthost.get_asic_namespace_list() - asic_namespace = random.choice(namespace_list) - asic_index = duthost.get_asic_id_from_namespace(asic_namespace) - - return asic_namespace, asic_index + if "rand_one_dut_front_end_hostname" in request.fixturenames: + dut_hostname = request.getfixturevalue("rand_one_dut_front_end_hostname") + else: + dut_hostname = rand_one_dut_hostname -@pytest.fixture(scope="module") -def rand_front_end_asic_namespace(duthosts, rand_one_dut_front_end_hostname): - """ - Return the randomly selected asic namespace in case of multi-asic frontend duthost. - """ - duthost = duthosts[rand_one_dut_front_end_hostname] + duthost = duthosts[dut_hostname] asic_namespace = None asic_index = None