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 pfcwd interval config tests #4811

Merged
merged 7 commits into from
Feb 8, 2022
Merged
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
157 changes: 157 additions & 0 deletions tests/generic_config_updater/test_pfcwd_interval.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import logging
import json
import pytest

from tests.common.helpers.assertions import pytest_assert
from tests.common.utilities import wait_until
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
from tests.generic_config_updater.gu_utils import create_checkpoint, delete_checkpoint, rollback_or_reload

pytestmark = [
pytest.mark.asic('mellanox')
]

logger = logging.getLogger(__name__)

READ_FLEXCOUNTER_DB_TIMEOUT = 480
READ_FLEXCOUNTER_DB_INTERVAL = 20


@pytest.fixture(scope="module")
def ensure_dut_readiness(duthost):
"""
Setup/teardown fixture for pfcwd interval config update tst

Args:
duthost: DUT host object
"""
create_checkpoint(duthost)

yield

try:
logger.info("Rolled back to original checkpoint")
rollback_or_reload(duthost)
finally:
delete_checkpoint(duthost)


def ensure_application_of_updated_config(duthost, value):
"""
Ensures application of the JSON patch config update by verifying field value presence in FLEX COUNTER DB

Args:
duthost: DUT host object
value: expected value of POLL_INTERVAL
"""
def _confirm_value_in_flex_counter_db():
poll_interval = duthost.shell('sonic-db-cli PFC_WD_DB hget FLEX_COUNTER_GROUP_TABLE:PFC_WD POLL_INTERVAL')["stdout"]
return value == poll_interval

pytest_assert(
wait_until(READ_FLEXCOUNTER_DB_TIMEOUT, READ_FLEXCOUNTER_DB_INTERVAL, 0, _confirm_value_in_flex_counter_db),
"FLEX COUNTER DB does not properly reflect newly POLL_INTERVAL expected value: {}".format(value)
)


def prepare_pfcwd_interval_config(duthost, value):
"""
Prepares config db by setting pfcwd poll interval to specified value. If value is empty string, delete the current entry.

Args:
duthost: DUT host object
value: poll interval value to be set
"""

logger.info("Setting configdb entry pfcwd poll interval to value: {}".format(value))

if value:
cmd = "pfcwd interval {}".format(value)
else:
cmd = "sonic-db-cli CONFIG_DB del \PFC_WD\GLOBAL\POLL_INTERVAL"

duthost.shell(cmd)

Copy link
Contributor

Choose a reason for hiding this comment

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

Seems we didn't run the cmd?


def get_detection_restoration_times(duthost):
"""
Returns detection_time, restoration_time for an interface. Poll_interval must be greater than both in order to be valid

Args:
duthost: DUT host object
"""

pfcwd_config = duthost.shell("show pfcwd config")
pytest_assert(not pfcwd_config['rc'], "Unable to read pfcwd config")

for line in pfcwd_config['stdout_lines']:
if line.startswith('Ethernet'):
interface = line.split()[0] # Since line starts with Ethernet, we can safely use 0 index

cmd = "sonic-db-cli CONFIG_DB hget \"PFC_WD|{}\" \"detection_time\" ".format(interface)
output = duthost.shell(cmd, module_ignore_errors=True)
pytest_assert(not output['rc'], "Unable to read detection time")
detection_time = output["stdout"]

cmd = "sonic-db-cli CONFIG_DB hget \"PFC_WD|{}\" \"restoration_time\" ".format(interface)
output = duthost.shell(cmd, module_ignore_errors=True)
pytest_assert(not output['rc'], "Unable to read restoration time")
restoration_time = output["stdout"]

return int(detection_time), int(restoration_time)

pytest_assert(True, "Failed to read detection_time and/or restoration time")


def get_new_interval(duthost, is_valid):
"""
Returns new interval value for pfcwd poll interval, based on the operation being performed

Args:
duthost: DUT host object
is_valid: if is_valid is true, return a valid new interval. Config update should succeed. If is_valid is false, return an invalid new interval. Config update should fail.
"""

detection_time, restoration_time = get_detection_restoration_times(duthost)
if is_valid:
return max(detection_time, restoration_time) - 10
else:
return min(detection_time, restoration_time) + 10


@pytest.mark.parametrize("operation", ["add", "replace"])
@pytest.mark.parametrize("field_pre_status", ["existing", "nonexistent"])
@pytest.mark.parametrize("is_valid_config_update", [True, False])
def test_pfcwd_interval_config_updates(duthost, ensure_dut_readiness, operation, field_pre_status, is_valid_config_update):
isabelmsft marked this conversation as resolved.
Show resolved Hide resolved
new_interval = get_new_interval(duthost, is_valid_config_update)

operation_to_new_value_map = {"add": "{}".format(new_interval), "replace": "{}".format(new_interval), "remove": ""}
detection_time, restoration_time = get_detection_restoration_times(duthost)
pre_status = max(detection_time, restoration_time)
field_pre_status_to_value_map = {"existing": "{}".format(pre_status), "nonexistent": ""}

prepare_pfcwd_interval_config(duthost, field_pre_status_to_value_map[field_pre_status])

tmpfile = generate_tmpfile(duthost)
logger.info("tmpfile {} created for json patch of pfcwd poll interval and operation: {}".format(tmpfile, operation))
value = operation_to_new_value_map[operation]
logger.info("value to be added to json patch: {}".format(value))

json_patch = [
{
"op": "{}".format(operation),
"path": "/PFC_WD/GLOBAL/POLL_INTERVAL",
"value": "{}".format(value)
}]

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

if is_valid_config_update:
expect_op_success(duthost, output)
ensure_application_of_updated_config(duthost, value)
else:
expect_op_failure(output)
finally:
delete_tmpfile(duthost, tmpfile)