diff --git a/tests/common/helpers/dut_utils.py b/tests/common/helpers/dut_utils.py index 8f9ebd7a1d6..17b3df8ce32 100644 --- a/tests/common/helpers/dut_utils.py +++ b/tests/common/helpers/dut_utils.py @@ -260,3 +260,23 @@ def verify_features_state(duthost): logger.info("The state of '{}' is valid.".format(feature_name)) return True + + +def verify_orchagent_running_or_assert(duthost): + """ + Verifies that orchagent is running, asserts otherwise + + Args: + duthost: Device Under Test (DUT) + """ + + def _orchagent_running(): + cmds = 'docker exec swss supervisorctl status orchagent' + output = duthost.shell(cmds, module_ignore_errors=True) + pytest_assert(not output['rc'], "Unable to check orchagent status output") + return 'RUNNING' in output['stdout'] + + pytest_assert( + wait_until(120, 10, 0, _orchagent_running), + "Orchagent is not running" + ) diff --git a/tests/generic_config_updater/test_incremental_qos.py b/tests/generic_config_updater/test_incremental_qos.py new file mode 100644 index 00000000000..abe422e6ee6 --- /dev/null +++ b/tests/generic_config_updater/test_incremental_qos.py @@ -0,0 +1,93 @@ +import logging +import json +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 +from tests.common.helpers.dut_utils import verify_orchagent_running_or_assert +from tests.generic_config_updater.gu_utils import apply_patch, expect_op_success, expect_res_success, expect_op_failure +from tests.generic_config_updater.gu_utils import generate_tmpfile, delete_tmpfile + +pytestmark = [ + pytest.mark.topology('t0'), + pytest.mark.asic('mellanox') +] + +logger = logging.getLogger(__name__) + + +@pytest.fixture(scope="module") +def ensure_dut_readiness(duthost): + """ + Setup/teardown fixture for incremental qos config update tst + + Args: + duthost: DUT host object + """ + config_tmpfile = generate_tmpfile(duthost) + logger.info("config_tmpfile {}".format(config_tmpfile)) + logger.info("Backing up config_db.json") + duthost.shell("sudo cp /etc/sonic/config_db.json {}".format(config_tmpfile)) + verify_orchagent_running_or_assert(duthost) + + yield + + verify_orchagent_running_or_assert(duthost) + logger.info("Restoring config_db.json") + duthost.shell("sudo cp {} /etc/sonic/config_db.json".format(config_tmpfile)) + delete_tmpfile(duthost, config_tmpfile) + config_reload(duthost) + + logger.info("TEARDOWN COMPLETED") + + +def prepare_configdb_field(duthost, configdb_field, value): + """ + Prepares config db by setting BUFFER_POOL key and field to specified value. If value is empty string or None, delete the current entry. + + Args: + duthost: DUT host object + configdb_field: field in config_db BUFFER_POOL table of the form key/value + value: BUFFER_POOL table value to be set + """ + + configdb_field_elements = configdb_field.split('/') + pytest_assert((len(configdb_field_elements) == 2), "Configdb field not identifiable") + + key = configdb_field_elements[0] + field = configdb_field_elements[1] + logger.info("Setting configdb key: {} field: {} to value: {}".format(key, field, value)) + + if value: + cmd = "sonic-db-cli CONFIG_DB hset \"BUFFER_POOL|{}\" \"{}\" \"{}\" ".format(key, field, value) + else: + cmd = "sonic-db-cli CONFIG_DB del \"BUFFER_POOL|{}\" \"{}\" ".format(key, field) + + verify_orchagent_running_or_assert(duthost) + + +@pytest.mark.parametrize("configdb_field", ["ingress_lossless_pool/xoff", "ingress_lossless_pool/size", "egress_lossy_pool/size"]) +@pytest.mark.parametrize("operation", ["add", "replace", "remove"]) +@pytest.mark.parametrize("field_pre_status", ["existing", "nonexistent"]) +def test_incremental_qos_config_updates(duthost, ensure_dut_readiness, configdb_field, operation, field_pre_status): + operation_to_new_value_map = {"add": "678", "replace": "789", "remove": ""} + field_pre_status_to_value_map = {"existing": "567", "nonexistent": ""} + + prepare_configdb_field(duthost, configdb_field, field_pre_status_to_value_map[field_pre_status]) + + tmpfile = generate_tmpfile(duthost) + logger.info("tmpfile {} created for json patch of field: {} and operation: {}".format(tmpfile, configdb_field, operation)) + + json_patch = [ + { + "op": "{}".format(operation), + "path": "/BUFFER_POOL/{}".format(configdb_field), + "value": "{}".format(operation_to_new_value_map[operation]) + } + ] + + output = apply_patch(duthost, json_data=json_patch, dest_file=tmpfile) + expect_op_success(duthost, output) + + delete_tmpfile(duthost, tmpfile)