From a8bd27f2df05e39610fec83eabcbab08302f5f2a Mon Sep 17 00:00:00 2001 From: Alon Navarro Date: Wed, 21 Jun 2023 23:57:27 +0300 Subject: [PATCH 01/24] clock tests --- tests/clock/ClockConsts.py | 43 +++++ tests/clock/ClockUtils.py | 366 +++++++++++++++++++++++++++++++++++++ tests/clock/conftest.py | 71 +++++++ tests/clock/test_clock.py | 191 +++++++++++++++++++ 4 files changed, 671 insertions(+) create mode 100755 tests/clock/ClockConsts.py create mode 100755 tests/clock/ClockUtils.py create mode 100755 tests/clock/conftest.py create mode 100755 tests/clock/test_clock.py diff --git a/tests/clock/ClockConsts.py b/tests/clock/ClockConsts.py new file mode 100755 index 00000000000..45f705758ca --- /dev/null +++ b/tests/clock/ClockConsts.py @@ -0,0 +1,43 @@ + +class ClockConsts: + STDOUT = "stdout" + STDERR = "stderr" + + DATE = "date" + TIME = "time" + TIMEZONE = "timezone" + + TEST_TIMEZONE = "Asia/Jerusalem" + TIME_MARGIN = 6 + RANDOM_NUM = 6 + + # sonic commands + CMD_SHOW_CLOCK = "show clock" + CMD_SHOW_CLOCK_TIMEZONES = "show clock timezones" + CMD_CONFIG_CLOCK_TIMEZONE = "config clock timezone" + CMD_CONFIG_CLOCK_DATE = "config clock date" + + # expected outputs + OUTPUT_CMD_SUCCESS = '' + + # expected errors + ERR_BAD_TIMEZONE = 'Timezone {} does not conform format' + ERR_MISSING_DATE = 'Error: Missing argument ""' + ERR_MISSING_TIME = 'Error: Missing argument ""' + ERR_BAD_DATE = 'Date {} does not conform format YYYY-MM-DD' + ERR_BAD_TIME = 'Time {} does not conform format HH:MM:SS' + + # timedatectl + CMD_TIMEDATECTL = "timedatectl" + TIME_ZONE = "Time zone" + + MIN_SYSTEM_DATE = "1970-01-01" + MAX_SYSTEM_DATE = "2231-12-31" + + # ntp + CMD_SHOW_NTP = "show ntp" + CMD_CONFIG_NTP_ADD = "config ntp add" + CMD_CONFIG_NTP_DEL = "config ntp del" + OUTPUT_CMD_NTP_ADD_SUCCESS = 'NTP server {} added to configuration\nRestarting ntp-config service...' + OUTPUT_CMD_NTP_DEL_SUCCESS = 'NTP server {} removed from configuration\nRestarting ntp-config service...' + REGEX_NTP_POLLING_TIME = r'polling server every (\d+)' diff --git a/tests/clock/ClockUtils.py b/tests/clock/ClockUtils.py new file mode 100755 index 00000000000..3914d48012d --- /dev/null +++ b/tests/clock/ClockUtils.py @@ -0,0 +1,366 @@ +import logging +import random +import datetime +import allure +import pytest +import time +from tests.common.helpers.assertions import pytest_assert +from tests.clock.ClockConsts import ClockConsts +from tests.common.errors import RunAnsibleModuleFail + + +class ClockUtils: + @staticmethod + def run_cmd(duthosts, cmd, param=''): + """ + @summary: + Run a given command and return it's output. + * a successful command returns empty output (''), while failure returns error message + @return: commands output (str) + """ + with allure.step('Run command: "{}" with param "{}"'.format(cmd, param)): + logging.info('Run command: "{}" with param "{}"'.format(cmd, param)) + DUT_HOSTNAME = duthosts[0].hostname + + cmd_to_run = cmd if param == '' else cmd + ' ' + param + logging.info('Actual command to run: "{}"'.format(cmd_to_run)) + + try: + cmd_output = duthosts.command(cmd_to_run)[DUT_HOSTNAME][ClockConsts.STDOUT] + except RunAnsibleModuleFail as cmd_err: + output = cmd_err.results[ClockConsts.STDOUT] + err = cmd_err.results[ClockConsts.STDERR] + cmd_output = output if output else err + logging.info('Command Error!\nError message: "{}"'.format(cmd_output)) + logging.info('Output type: {}'.format(type(cmd_output))) + logging.info('Output: {}'.format(cmd_output)) + + with allure.step('Convert output to string'): + logging.info('Convert output to string') + cmd_output = str(cmd_output) + logging.info('Output type: {}'.format(type(cmd_output))) + logging.info('Output: {}'.format(cmd_output)) + return cmd_output + + @staticmethod + def parse_show_clock_output(show_clock_output): + """ + @summary: + Split output of show clock into date, time and timezone strings + + Exapmple: + "Mon 03 Apr 2023 11:29:46 AM UTC" -> {"date": "Mon 03 Apr 2023", "time": "11:29:46 AM", "timezone": "UTC"} + @param show_clock_output: the given show clock output + @return: The splited output as a dict + """ + with allure.step('Split output of show clock'): + logging.info('Split output of show clock') + output_list = show_clock_output.split(' ') + date = ' '.join(output_list[0:4]) + time = ' '.join(output_list[4:6]) + timezone = ' '.join(output_list[6:]) + logging.info('Splited output:\ndate: "{}"\ntime: "{}"\ntimezone: "{}"'.format(date, time, timezone)) + + res = { + ClockConsts.DATE: date, + ClockConsts.TIME: time, + ClockConsts.TIMEZONE: timezone + } + logging.info('res dict: {}'.format(res)) + + return res + + @staticmethod + def parse_linux_cmd_output(linux_cmd_output): + """ + @summary: + Parse output of a linux command. + + Example: + timedatectl's output: + "Local time: Tue 2023-04-04 08:22:01 MDT + Universal time: Tue 2023-04-04 14:22:01 UTC + RTC time: Tue 2023-04-04 14:22:01 + Time zone: America/Inuvik (MDT, -0600) + System clock synchronized: no + NTP service: n/a + RTC in local TZ: no" + + will become: + { + "Local time": "Tue 2023-04-04 08:22:01 MDT", + "Universal time": "Tue 2023-04-04 14:22:01 UTC", + ... + } + @param linux_cmd_output: given output of a linux command (str) + @return: dictionary as mentioned in the example + """ + with allure.step('Parse linux command output into dictionary'): + logging.info('Parse linux command output into dictionary') + rows = [row.strip() for row in linux_cmd_output.split('\n')] # split by rows + logging.info('rows: {}'.format(rows)) + res_dict = {} + for row in rows: + logging.info('row: "{}"'.format(row)) + idx = row.index(':') + k, v = row[0: idx], row[idx + 2:] + res_dict[k] = v + logging.info('Result dict:\n{}'.format(res_dict)) + return res_dict + + @staticmethod + def validate_date(date_str): + """ + @summary: + Verify that given string is in a good date format: "Mon 03 Apr 2023" + @param date_str: the given string + """ + with allure.step('Validate date for: "{}"'.format(date_str)): + logging.info('Validate date for: "{}"'.format(date_str)) + try: + datetime.datetime.strptime(date_str, "%a %d %b %Y") + logging.info('Validate date success') + except ValueError: + logging.info('Validate date fail') + pytest_assert(False, 'Given string "{}" is not a valid date'.format(date_str)) + + @staticmethod + def validate_time(time_str): + """ + @summary: + Verify that given string is in a good time format: "11:29:46 AM" (or PM) + @param time_str: the given string + """ + with allure.step('Validate time for: "{}"'.format(time_str)): + logging.info('Validate time for: "{}"'.format(time_str)) + try: + datetime.datetime.strptime(time_str, "%I:%M:%S %p") + logging.info('Validate time success') + except ValueError: + logging.info('Validate time fail') + pytest_assert(False, 'Given string "{}" is not a valid time'.format(time_str)) + + @staticmethod + def get_valid_timezones(duthosts): + """ + @summary: + Get the list of valid timezones from 'show clock timezones' command + @param duthosts: duthosts object + @return: list of timezones (strings) + """ + with allure.step('Get list of valid timezones from show clock timezones command'): + logging.info('Get list of valid timezones from show clock timezones command') + return ClockUtils.run_cmd(duthosts=duthosts, cmd=ClockConsts.CMD_SHOW_CLOCK_TIMEZONES).split() + + @staticmethod + def validate_timezone(timezone_str, duthosts): + """ + @summary: + Verify that the given string is an abbreviation of a valid timezone + @param timezone_str: the given string + @param duthosts: duthosts + """ + with allure.step('Verify that given string "{}" is a valid timezone'.format(timezone_str)): + logging.info('Verify that given string "{}" is a valid timezone'.format(timezone_str)) + + with allure.step('Get timezone from timedatectl linux command'): + logging.info('Get timezone from timedatectl linux command') + timedatectl_output = ClockUtils.parse_linux_cmd_output(ClockUtils.run_cmd(duthosts, ClockConsts.CMD_TIMEDATECTL)) + timedatectl_timezone = timedatectl_output[ClockConsts.TIME_ZONE] + timedatectl_tz_name = timedatectl_timezone.split()[0] + timedatectl_tz_abbreviation = timedatectl_timezone.split(' ')[1].split(',')[0].replace('(', '') + logging.info('Timezone in timedatectl: "{}"\nTimezone name: "{}"\nTimezone abbreviation: "{}"' + .format(timedatectl_timezone, timedatectl_tz_name, timedatectl_tz_abbreviation)) + + with allure.step('Verify timezone name "{}" from timedatectl is in valid timezones'.format(timedatectl_tz_name)): + logging.info('Verify timezone name "{}" from timedatectl is in valid timezones'.format(timedatectl_tz_name)) + valid_timezones = ClockUtils.get_valid_timezones(duthosts) + pytest_assert(timedatectl_tz_name in valid_timezones, + 'Error: string "{}" is not in the valid timezones list'.format(timezone_str)) + + with allure.step('Verify that the given timezone "{}" equals to timezone abbreviation in timedatectl "{}"'.format(timezone_str, timedatectl_tz_abbreviation)): + logging.info('Verify that the given timezone "{}" equals to timezone abbreviation in timedatectl "{}"'.format(timezone_str, timedatectl_tz_abbreviation)) + ClockUtils.verify_value(expected=timedatectl_tz_abbreviation, actual=timezone_str) + + @staticmethod + def verify_value(expected, actual, should_be_equal=True): + """ + @summary: + Asserts a given value is as expected + @param expected: expected value + @param actual: actual given value + """ + expected_to_print = "''" if expected == '' else expected + actual_to_print = "''" if actual == '' else actual + + if should_be_equal: + with allure.step('Verify that actual value - {} is as expected - {}'.format(expected_to_print, actual_to_print)): + logging.info('Verify that actual value - {} is as expected - {}'.format(expected_to_print, actual_to_print)) + pytest_assert(actual == expected, 'Error: Values are not equal.\nExpected: {}\t{}\nActual: {}\t{}' + .format(expected_to_print, type(expected), actual_to_print, type(actual))) + else: + with allure.step('Verify that actual value - {} is different than expected - {}'.format(expected_to_print, actual_to_print)): + logging.info('Verify that actual value - {} is different than expected - {}'.format(expected_to_print, actual_to_print)) + pytest_assert(actual != expected, 'Error: Values are equal.\nExpected: {}\t{}\nActual: {}\t{}' + .format(expected_to_print, type(expected), actual_to_print, type(actual))) + + @staticmethod + def verify_substring(expected_substr, whole_str): + """ + @summary: + Asserts that a given string contains an expected substring + @param expected_substr: expected substring + @param whole_str: the whole string + """ + with allure.step('Verify that string "{}" contains the substring "{}"'.format(whole_str, expected_substr)): + logging.info('Verify that string "{}" contains the substring "{}"'.format(whole_str, expected_substr)) + pytest_assert(expected_substr in whole_str, + 'Error: The given string does not contain the expected substring.\n' + 'Expected substring: "{}"\n' + 'Given (whole) string: "{}"'.format(expected_substr, whole_str)) + + @ staticmethod + def verify_command(cmd_output, should_succeed=True, expected_err=''): + """ + @summary: + Verify command success/failure + * doesn't apply on show command + * in case of failure, user can specify an expected error message to be contained in the output + @param cmd_output: the command's output + @param should_succeed: whether the command should succeed or not + @param expected_err: expected error message + """ + if should_succeed: + with allure.step('Verify that command succeeded'): + logging.info('Verify that command succeeded') + ClockUtils.verify_value(expected=ClockConsts.OUTPUT_CMD_SUCCESS, actual=cmd_output) + else: + with allure.step('Verify that command failed and output contains "{}"'.format(expected_err)): + logging.info('Verify that command failed and output contains "{}"'.format(expected_err)) + ClockUtils.verify_substring(expected_substr=expected_err, whole_str=cmd_output) + + @ staticmethod + def verify_timezone_value(duthosts, tz_name, tz_abbreviation): + """ + @summary: + Verify that a given timezone abbreviation matches the expected timezone. + * Given timezone abbreviation from show clock command (ETC, IDT, etc.) + * Assume that expected timezone should be given as a complete timezone name (ETC/UTC, Asia/Jerusalem, etc.) + @param duthosts: duthosts object + @param tz_name: The expected timezone + @param tz_abbreviation: The actual given timezone abbreviation + """ + with allure.step('Verify that given timezone abbreviation "{}" matches to expected timezone "{}"'.format(tz_abbreviation, tz_name)): + logging.info('Verify that given timezone abbreviation "{}" matches to expected timezone "{}"'.format(tz_abbreviation, tz_name)) + + with allure.step('Get timezone details from timedatectl command'): + logging.info('Get timezone details from timedatectl command') + timedatectl_output = ClockUtils.parse_linux_cmd_output(ClockUtils.run_cmd(duthosts, ClockConsts.CMD_TIMEDATECTL)) + timedatectl_timezone = timedatectl_output[ClockConsts.TIME_ZONE] + timedatectl_tz_name = timedatectl_timezone.split()[0] + timedatectl_tz_abbreviation = timedatectl_timezone.split(' ')[1].split(',')[0].replace('(', '') + logging.info('Timezone in timedatectl: "{}"\nTimezone name: "{}"\nTimezone abbreviation: "{}"' + .format(timedatectl_timezone, timedatectl_tz_name, timedatectl_tz_abbreviation)) + + with allure.step('Check that given timezone "{}" equals to timezone in timedatectl "{}"'.format(tz_name, timedatectl_tz_name)): + logging.info('Check that given timezone "{}" equals to timezone in timedatectl "{}"'.format(tz_name, timedatectl_tz_name)) + ClockUtils.verify_value(expected=timedatectl_tz_name, actual=tz_name) + + with allure.step('Check that given timezone abbreviation "{}" matches the expected timezone "{}"'.format(tz_abbreviation, tz_name)): + logging.info('Check that given timezone abbreviation "{}" matches the expected timezone "{}"'.format(tz_abbreviation, tz_name)) + ClockUtils.verify_value(expected=timedatectl_tz_abbreviation, actual=tz_abbreviation) + + @ staticmethod + def select_random_date(): + """ + @summary: + Select a random date + @return: a random date as string in the format "YYYY-MM-DD" + """ + with allure.step('Select a random date'): + logging.info('Select a random date') + start_date = datetime.date.fromisoformat(ClockConsts.MIN_SYSTEM_DATE) + end_date = datetime.date.fromisoformat(ClockConsts.MAX_SYSTEM_DATE) + + diff_days = (end_date - start_date).days + + rand_num_of_days = random.randint(0, diff_days) + + rand_date = start_date + datetime.timedelta(days=rand_num_of_days) + + rand_date_str = rand_date.strftime('%Y-%m-%d') + + logging.info('Selected random date: "{}"'.format(rand_date_str)) + return rand_date_str + + @ staticmethod + def select_random_time(): + """ + @summary: + Select a random time + @return: a random date as string in the format "hh:mm:ss" + """ + with allure.step('Select a random time in a day'): + logging.info('Select a random time in a day') + rand_num_of_seconds_since_00 = random.randint(0, 24 * 60 * 60 - 1) + + rand_time_obj = time.gmtime(rand_num_of_seconds_since_00) + + rand_time_str = time.strftime("%H:%M:%S", rand_time_obj) + + logging.info('Selected random time: "{}"'.format(rand_time_str)) + return rand_time_str + + @ staticmethod + def convert_show_clock_date(show_clock_date): + """ + @summary: + Convert date from show clock to format "YYYY-MM-DD" + e.g. "Wed 12 Apr 2023" --> "2023-04-12" + @param show_clock_date: given date from show clock + @return: converted date + """ + with allure.step('Convert date "{}" to format "YYYY-MM-DD"'.format(show_clock_date)): + logging.info('Convert date "{}" to format "YYYY-MM-DD"'.format(show_clock_date)) + converted_date = datetime.datetime.strptime(show_clock_date, "%a %d %b %Y").strftime("%Y-%m-%d") + logging.info('Converted date: "{}"'.format(converted_date)) + return converted_date + + @ staticmethod + def convert_show_clock_time(show_clock_time): + """ + @summary: + Convert time from show clock to format "hh:mm:ss" + e.g. "02:14:28 PM" --> "14:14:28" + @param show_clock_time: given time from show clock + @return: converted me + """ + with allure.step('Convert time "{}" to format "hh:mm:ss"'.format(show_clock_time)): + logging.info('Convert time "{}" to format "hh:mm:ss"'.format(show_clock_time)) + converted_time = datetime.datetime.strptime(show_clock_time, "%I:%M:%S %p").strftime("%H:%M:%S") + logging.info('Converted time: "{}"'.format(converted_time)) + return converted_time + + @ staticmethod + def verify_time(expected, actual, allowed_margin=ClockConsts.TIME_MARGIN): + """ + @summary: + Asserts a given time value is as expected + * expected and actual time values are strings in the format "HH:MM:SS" + @param expected: expected time value + @param actual: actual given time value + @param allowed_margin: allowed margin between two times (in seconds) + """ + with allure.step('Verify that diff between "{}" and "{}" (in seconds) is no longer than {}'.format(expected, actual, allowed_margin)): + logging.info('Verify that diff between "{}" and "{}" (in seconds) is no longer than {}'.format(expected, actual, allowed_margin)) + + with allure.step('Calculate diff between "{}" and "{}" in seconds'.format(expected, actual)): + logging.info('Calculate diff between "{}" and "{}" in seconds'.format(expected, actual)) + time_obj1 = datetime.datetime.strptime(expected, "%H:%M:%S") + time_obj2 = datetime.datetime.strptime(actual, "%H:%M:%S") + + diff_seconds = abs((time_obj2 - time_obj1).total_seconds()) + + with allure.step('Verify that actual diff {} is not larger than {}'.format(diff_seconds, allowed_margin)): + logging.info('Verify that actual diff {} is not larger than {}'.format(diff_seconds, allowed_margin)) + ClockUtils.verify_value(True, diff_seconds <= allowed_margin) diff --git a/tests/clock/conftest.py b/tests/clock/conftest.py new file mode 100755 index 00000000000..fc7419f61a5 --- /dev/null +++ b/tests/clock/conftest.py @@ -0,0 +1,71 @@ +import re +import time +import pytest +import logging + +from tests.clock.ClockConsts import ClockConsts +from tests.clock.ClockUtils import ClockUtils + + +def pytest_addoption(parser): + parser.addoption("--ntp_server", action="store", default=None, help="IP of NTP server to use") + + +@pytest.fixture(scope='session', autouse=True) +def ntp_server(request): + """ + @summary: Return NTP server's ip if given, otherwise skip the test + """ + ntp_server_ip = request.config.getoption("ntp_server") + logging.info('NTP server ip from execution parameter: {}'.format(ntp_server_ip)) + if ntp_server_ip is None: + logging.info('IP of NTP server was not given, will not run the test') + pytest.skip("IP of NTP server was not given, will not run the test") + return ntp_server_ip + + +@pytest.fixture(scope="function") +def init_timezone(duthosts): + """ + @summary: fixture to init timezone before and after each test + """ + + logging.info('Set timezone to {} before test'.format(ClockConsts.TEST_TIMEZONE)) + ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, ClockConsts.TEST_TIMEZONE) + + yield + + logging.info('Set timezone to {} after test'.format(ClockConsts.TEST_TIMEZONE)) + ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, ClockConsts.TEST_TIMEZONE) + + +@pytest.fixture(scope="function") +def restore_time(duthosts, ntp_server): + """ + @summary: fixture to restore time after test (using ntp) + """ + + yield + + logging.info('Reset time after test. Sync with NTP server: {}') + + logging.info('Sync with NTP server: {}'.format(ntp_server)) + ClockUtils.verify_substring(ClockConsts.OUTPUT_CMD_NTP_ADD_SUCCESS.format(ntp_server), + ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_NTP_ADD, ntp_server)) + + logging.info('Check polling time') + show_ntp_output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_NTP) + match = re.search(ClockConsts.REGEX_NTP_POLLING_TIME, show_ntp_output) + if match: + polling_time_seconds = int(match.group(1)) + else: + logging.info('Could not match the regex.\nPattern: "{}"\nShow ntp output string: "{}"'.format(ClockConsts.REGEX_NTP_POLLING_TIME, show_ntp_output)) + polling_time_seconds = ClockConsts.RANDOM_NUM + logging.info('Polling time (in seconds): {}'.format(polling_time_seconds + 1)) + + logging.info('Wait for the sync') + time.sleep(polling_time_seconds) + + logging.info('Delete NTP server: {}'.format(ntp_server)) + ClockUtils.verify_substring(ClockConsts.OUTPUT_CMD_NTP_DEL_SUCCESS.format(ntp_server), + ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_NTP_DEL, ntp_server)) diff --git a/tests/clock/test_clock.py b/tests/clock/test_clock.py new file mode 100755 index 00000000000..6af19a74c94 --- /dev/null +++ b/tests/clock/test_clock.py @@ -0,0 +1,191 @@ +import logging +import random +import string + +import pytest +import allure +from datetime import datetime +from tests.common.helpers.assertions import pytest_assert +from tests.clock.ClockUtils import ClockUtils +from tests.clock.ClockConsts import ClockConsts + +pytestmark = [ + pytest.mark.topology('any'), + pytest.mark.sanity_check(skip_sanity=True), + pytest.mark.disable_loganalyzer, + pytest.mark.skip_check_dut_health, + pytest.mark.clock +] + + +def test_show_clock(duthosts, init_timezone): + """ + @summary: + Test that show clock output is correct + + Steps: + 1. Run show clock + 2. Validate info + """ + with allure.step('Run show clock command'): + logging.info('Run show clock command') + show_clock_output = ClockUtils.run_cmd(duthosts=duthosts, cmd=ClockConsts.CMD_SHOW_CLOCK) + + with allure.step('Verify info is valid'): + logging.info('Verify info is valid') + output_dict = ClockUtils.parse_show_clock_output(show_clock_output) + ClockUtils.validate_date(output_dict[ClockConsts.DATE]) + ClockUtils.validate_time(output_dict[ClockConsts.TIME]) + ClockUtils.validate_timezone(output_dict[ClockConsts.TIMEZONE], duthosts) + + +def test_config_clock_timezone(duthosts, init_timezone): + """ + @summary: + Check that 'config clock timezone' command works correctly + + Steps: + 1. Set a new valid timezone + 2. Verify timezone changed + 3. Set invalid timezone + 4. Verify timezone hasn't changed + """ + valid_timezones = ClockUtils.get_valid_timezones(duthosts) + orig_timezone = ClockUtils \ + .parse_show_clock_output(ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK))[ClockConsts.TIMEZONE] + + with allure.step('Select a random new valid timezone'): + logging.info('Select a random new valid timezone') + new_timezone = random.choice(valid_timezones) + while new_timezone == orig_timezone: + new_timezone = random.choice(valid_timezones) + + with allure.step('Set the new timezone "{}"'.format(new_timezone)): + logging.info('Set the new timezone "{}"'.format(new_timezone)) + output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, new_timezone) + + with allure.step('Verify command success'): + logging.info('Verify command success') + ClockUtils.verify_command(cmd_output=output, should_succeed=True) + + with allure.step('Verify timezone changed to "{}"'.format(new_timezone)): + logging.info('Verify timezone changed to "{}"'.format(new_timezone)) + cur_timezone = ClockUtils \ + .parse_show_clock_output(ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK))[ClockConsts.TIMEZONE] + ClockUtils.verify_timezone_value(duthosts, tz_name=new_timezone, tz_abbreviation=cur_timezone) + + with allure.step('Select a random string as invalid timezone'): + logging.info('Select a random string as invalid timezone') + invalid_timezone = ''.join(random.choice(string.ascii_lowercase) for _ in range(random.randint(1, 10))) + while invalid_timezone in valid_timezones: + invalid_timezone = ''.join(random.choice(string.ascii_lowercase) for _ in range(random.randint(1, 10))) + logging.info('Selected invalid timezone: "{}"'.format(invalid_timezone)) + + with allure.step('Try to set the invalid timezone "{}"'.format(invalid_timezone)): + logging.info('Try to set the invalid timezone "{}"'.format(invalid_timezone)) + output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, invalid_timezone) + + with allure.step('Verify command failure'): + logging.info('Verify command failure') + ClockUtils.verify_command(cmd_output=output, should_succeed=False, expected_err=ClockConsts.ERR_BAD_TIMEZONE.format(invalid_timezone)) + + with allure.step('Verify timezone has not changed'): + logging.info('Verify timezone has not changed') + cur_timezone = ClockUtils \ + .parse_show_clock_output(ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK))[ClockConsts.TIMEZONE] + ClockUtils.verify_timezone_value(duthosts, tz_name=new_timezone, tz_abbreviation=cur_timezone) + + +def test_config_clock_date(duthosts, init_timezone, restore_time): + """ + @summary: + Check that 'config clock ate' command works correctly + + Steps: + 1. Set a new valid date and time using the command + 2. Verify date and time changed + 3. Try to set invalid date and time + 4. Verify error and that time hasn't changed + """ + with allure.step('Select valid date and time to set'): + logging.info('Select valid date and time to set') + new_date = ClockUtils.select_random_date() + new_time = ClockUtils.select_random_time() + new_datetime = new_date + ' ' + new_time + + with allure.step('Set new date and time "{}"'.format(new_datetime)): + logging.info('Set new date and time "{}"'.format(new_datetime)) + output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_DATE, new_datetime) + + with allure.step('Verify command success'): + logging.info('Verify command success') + ClockUtils.verify_command(cmd_output=output, should_succeed=True) + + with allure.step('Verify date and time changed to "{}"'.format(new_datetime)): + logging.info('Verify date and time changed to "{}"'.format(new_datetime)) + with allure.step('Get datetime from show clock'): + logging.info('Get datetime from show clock') + show_clock_output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) + show_clock_dict = ClockUtils.parse_show_clock_output(show_clock_output) + + with allure.step('Verify date'): + logging.info('Verify date') + cur_date = ClockUtils.convert_show_clock_date(show_clock_dict[ClockConsts.DATE]) + ClockUtils.verify_value(expected=new_date, actual=cur_date) + + with allure.step('Verify time'): + logging.info('Verify time') + cur_time = ClockUtils.convert_show_clock_time(show_clock_dict[ClockConsts.TIME]) + ClockUtils.verify_time(expected=new_time, actual=cur_time) + + with allure.step('Select random string as invalid input'): + logging.info('Select random string as invalid input') + rand_str = ''.join(random.choice(string.ascii_lowercase) for i in range(ClockConsts.RANDOM_NUM)) + logging.info('Selected random string: "{}"'.format(rand_str)) + + with allure.step('Try to set invalid inputs'): + logging.info('Try to set invalid inputs') + errors = { + '': ClockConsts.ERR_MISSING_DATE, + rand_str: ClockConsts.ERR_MISSING_TIME, + rand_str + ' ' + rand_str: ClockConsts.ERR_BAD_DATE.format(rand_str) + '\n' + ClockConsts.ERR_BAD_TIME.format(rand_str), + rand_str + ' ' + new_time: ClockConsts.ERR_BAD_DATE.format(rand_str), + new_date + ' ' + rand_str: ClockConsts.ERR_BAD_TIME.format(rand_str) + } + + i = 0 + for invalid_input, err_msg in errors.items(): + logging.info('Invalid input #{}: "{}"\nExpected error:\n{}'.format(i, invalid_input, err_msg)) + + with allure.step('Get show clock output before running the config command'): + logging.info('Get show clock output before running the config command') + show_clock_output_before = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) + + with allure.step('Try to set "{}"'.format(invalid_input)): + logging.info('Try to set "{}"'.format(invalid_input)) + output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_DATE, invalid_input) + + with allure.step('Get show clock output after running the config command'): + logging.info('Get show clock output after running the config command') + show_clock_output_after = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) + + with allure.step('Verify command failure'): + logging.info('Verify command failure') + ClockUtils.verify_command(cmd_output=output, should_succeed=False, expected_err=err_msg) + + with allure.step('Verify date and time have not changed (still "{}")'.format(new_datetime)): + logging.info('Verify date and time have not changed (still "{}")'.format(new_datetime)) + show_clock_dict_before = ClockUtils.parse_show_clock_output(show_clock_output_before) + show_clock_dict_after = ClockUtils.parse_show_clock_output(show_clock_output_after) + + with allure.step('Verify date'): + logging.info('Verify date') + ClockUtils.verify_value(expected=show_clock_dict_before[ClockConsts.DATE], actual=show_clock_dict_after[ClockConsts.DATE]) + + with allure.step('Verify time'): + logging.info('Verify time') + time_before = ClockUtils.convert_show_clock_time(show_clock_dict_before[ClockConsts.TIME]) + time_after = ClockUtils.convert_show_clock_time(show_clock_dict_after[ClockConsts.TIME]) + ClockUtils.verify_time(expected=time_before, actual=time_after) + + i += 1 From 16268f4b8bb0123dd95bd39dc1b709ecc7605be4 Mon Sep 17 00:00:00 2001 From: Alon Navarro Date: Wed, 21 Jun 2023 23:59:55 +0300 Subject: [PATCH 02/24] pre commit fixes --- tests/clock/ClockUtils.py | 54 ++++++++++++++++++++++++++------------- tests/clock/conftest.py | 3 ++- tests/clock/test_clock.py | 9 ++++--- 3 files changed, 44 insertions(+), 22 deletions(-) diff --git a/tests/clock/ClockUtils.py b/tests/clock/ClockUtils.py index 3914d48012d..b1720fe031b 100755 --- a/tests/clock/ClockUtils.py +++ b/tests/clock/ClockUtils.py @@ -165,21 +165,26 @@ def validate_timezone(timezone_str, duthosts): with allure.step('Get timezone from timedatectl linux command'): logging.info('Get timezone from timedatectl linux command') - timedatectl_output = ClockUtils.parse_linux_cmd_output(ClockUtils.run_cmd(duthosts, ClockConsts.CMD_TIMEDATECTL)) + timedatectl_output = \ + ClockUtils.parse_linux_cmd_output(ClockUtils.run_cmd(duthosts, ClockConsts.CMD_TIMEDATECTL)) timedatectl_timezone = timedatectl_output[ClockConsts.TIME_ZONE] timedatectl_tz_name = timedatectl_timezone.split()[0] timedatectl_tz_abbreviation = timedatectl_timezone.split(' ')[1].split(',')[0].replace('(', '') logging.info('Timezone in timedatectl: "{}"\nTimezone name: "{}"\nTimezone abbreviation: "{}"' .format(timedatectl_timezone, timedatectl_tz_name, timedatectl_tz_abbreviation)) - with allure.step('Verify timezone name "{}" from timedatectl is in valid timezones'.format(timedatectl_tz_name)): - logging.info('Verify timezone name "{}" from timedatectl is in valid timezones'.format(timedatectl_tz_name)) + with allure.step('Verify timezone name "{}" from timedatectl is in valid timezones' + .format(timedatectl_tz_name)): + logging.info('Verify timezone name "{}" from timedatectl is in valid timezones' + .format(timedatectl_tz_name)) valid_timezones = ClockUtils.get_valid_timezones(duthosts) pytest_assert(timedatectl_tz_name in valid_timezones, 'Error: string "{}" is not in the valid timezones list'.format(timezone_str)) - with allure.step('Verify that the given timezone "{}" equals to timezone abbreviation in timedatectl "{}"'.format(timezone_str, timedatectl_tz_abbreviation)): - logging.info('Verify that the given timezone "{}" equals to timezone abbreviation in timedatectl "{}"'.format(timezone_str, timedatectl_tz_abbreviation)) + with allure.step('Verify that the given timezone "{}" equals to timezone abbreviation in timedatectl "{}"' + .format(timezone_str, timedatectl_tz_abbreviation)): + logging.info('Verify that the given timezone "{}" equals to timezone abbreviation in timedatectl "{}"' + .format(timezone_str, timedatectl_tz_abbreviation)) ClockUtils.verify_value(expected=timedatectl_tz_abbreviation, actual=timezone_str) @staticmethod @@ -194,13 +199,17 @@ def verify_value(expected, actual, should_be_equal=True): actual_to_print = "''" if actual == '' else actual if should_be_equal: - with allure.step('Verify that actual value - {} is as expected - {}'.format(expected_to_print, actual_to_print)): - logging.info('Verify that actual value - {} is as expected - {}'.format(expected_to_print, actual_to_print)) + with allure.step('Verify that actual value - {} is as expected - {}' + .format(expected_to_print, actual_to_print)): + logging.info('Verify that actual value - {} is as expected - {}' + .format(expected_to_print, actual_to_print)) pytest_assert(actual == expected, 'Error: Values are not equal.\nExpected: {}\t{}\nActual: {}\t{}' .format(expected_to_print, type(expected), actual_to_print, type(actual))) else: - with allure.step('Verify that actual value - {} is different than expected - {}'.format(expected_to_print, actual_to_print)): - logging.info('Verify that actual value - {} is different than expected - {}'.format(expected_to_print, actual_to_print)) + with allure.step('Verify that actual value - {} is different than expected - {}' + .format(expected_to_print, actual_to_print)): + logging.info('Verify that actual value - {} is different than expected - {}' + .format(expected_to_print, actual_to_print)) pytest_assert(actual != expected, 'Error: Values are equal.\nExpected: {}\t{}\nActual: {}\t{}' .format(expected_to_print, type(expected), actual_to_print, type(actual))) @@ -250,24 +259,31 @@ def verify_timezone_value(duthosts, tz_name, tz_abbreviation): @param tz_name: The expected timezone @param tz_abbreviation: The actual given timezone abbreviation """ - with allure.step('Verify that given timezone abbreviation "{}" matches to expected timezone "{}"'.format(tz_abbreviation, tz_name)): - logging.info('Verify that given timezone abbreviation "{}" matches to expected timezone "{}"'.format(tz_abbreviation, tz_name)) + with allure.step('Verify that given timezone abbreviation "{}" matches to expected timezone "{}"' + .format(tz_abbreviation, tz_name)): + logging.info('Verify that given timezone abbreviation "{}" matches to expected timezone "{}"' + .format(tz_abbreviation, tz_name)) with allure.step('Get timezone details from timedatectl command'): logging.info('Get timezone details from timedatectl command') - timedatectl_output = ClockUtils.parse_linux_cmd_output(ClockUtils.run_cmd(duthosts, ClockConsts.CMD_TIMEDATECTL)) + timedatectl_output = \ + ClockUtils.parse_linux_cmd_output(ClockUtils.run_cmd(duthosts, ClockConsts.CMD_TIMEDATECTL)) timedatectl_timezone = timedatectl_output[ClockConsts.TIME_ZONE] timedatectl_tz_name = timedatectl_timezone.split()[0] timedatectl_tz_abbreviation = timedatectl_timezone.split(' ')[1].split(',')[0].replace('(', '') logging.info('Timezone in timedatectl: "{}"\nTimezone name: "{}"\nTimezone abbreviation: "{}"' .format(timedatectl_timezone, timedatectl_tz_name, timedatectl_tz_abbreviation)) - with allure.step('Check that given timezone "{}" equals to timezone in timedatectl "{}"'.format(tz_name, timedatectl_tz_name)): - logging.info('Check that given timezone "{}" equals to timezone in timedatectl "{}"'.format(tz_name, timedatectl_tz_name)) + with allure.step('Check that given timezone "{}" equals to timezone in timedatectl "{}"' + .format(tz_name, timedatectl_tz_name)): + logging.info('Check that given timezone "{}" equals to timezone in timedatectl "{}"' + .format(tz_name, timedatectl_tz_name)) ClockUtils.verify_value(expected=timedatectl_tz_name, actual=tz_name) - with allure.step('Check that given timezone abbreviation "{}" matches the expected timezone "{}"'.format(tz_abbreviation, tz_name)): - logging.info('Check that given timezone abbreviation "{}" matches the expected timezone "{}"'.format(tz_abbreviation, tz_name)) + with allure.step('Check that given timezone abbreviation "{}" matches the expected timezone "{}"' + .format(tz_abbreviation, tz_name)): + logging.info('Check that given timezone abbreviation "{}" matches the expected timezone "{}"' + .format(tz_abbreviation, tz_name)) ClockUtils.verify_value(expected=timedatectl_tz_abbreviation, actual=tz_abbreviation) @ staticmethod @@ -351,8 +367,10 @@ def verify_time(expected, actual, allowed_margin=ClockConsts.TIME_MARGIN): @param actual: actual given time value @param allowed_margin: allowed margin between two times (in seconds) """ - with allure.step('Verify that diff between "{}" and "{}" (in seconds) is no longer than {}'.format(expected, actual, allowed_margin)): - logging.info('Verify that diff between "{}" and "{}" (in seconds) is no longer than {}'.format(expected, actual, allowed_margin)) + with allure.step('Verify that diff between "{}" and "{}" (in seconds) is no longer than {}' + .format(expected, actual, allowed_margin)): + logging.info('Verify that diff between "{}" and "{}" (in seconds) is no longer than {}' + .format(expected, actual, allowed_margin)) with allure.step('Calculate diff between "{}" and "{}" in seconds'.format(expected, actual)): logging.info('Calculate diff between "{}" and "{}" in seconds'.format(expected, actual)) diff --git a/tests/clock/conftest.py b/tests/clock/conftest.py index fc7419f61a5..df09ad2ec8a 100755 --- a/tests/clock/conftest.py +++ b/tests/clock/conftest.py @@ -59,7 +59,8 @@ def restore_time(duthosts, ntp_server): if match: polling_time_seconds = int(match.group(1)) else: - logging.info('Could not match the regex.\nPattern: "{}"\nShow ntp output string: "{}"'.format(ClockConsts.REGEX_NTP_POLLING_TIME, show_ntp_output)) + logging.info('Could not match the regex.\nPattern: "{}"\nShow ntp output string: "{}"' + .format(ClockConsts.REGEX_NTP_POLLING_TIME, show_ntp_output)) polling_time_seconds = ClockConsts.RANDOM_NUM logging.info('Polling time (in seconds): {}'.format(polling_time_seconds + 1)) diff --git a/tests/clock/test_clock.py b/tests/clock/test_clock.py index 6af19a74c94..9449cf1232f 100755 --- a/tests/clock/test_clock.py +++ b/tests/clock/test_clock.py @@ -87,7 +87,8 @@ def test_config_clock_timezone(duthosts, init_timezone): with allure.step('Verify command failure'): logging.info('Verify command failure') - ClockUtils.verify_command(cmd_output=output, should_succeed=False, expected_err=ClockConsts.ERR_BAD_TIMEZONE.format(invalid_timezone)) + ClockUtils.verify_command(cmd_output=output, should_succeed=False, expected_err=ClockConsts.ERR_BAD_TIMEZONE + .format(invalid_timezone)) with allure.step('Verify timezone has not changed'): logging.info('Verify timezone has not changed') @@ -148,7 +149,8 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): errors = { '': ClockConsts.ERR_MISSING_DATE, rand_str: ClockConsts.ERR_MISSING_TIME, - rand_str + ' ' + rand_str: ClockConsts.ERR_BAD_DATE.format(rand_str) + '\n' + ClockConsts.ERR_BAD_TIME.format(rand_str), + rand_str + ' ' + rand_str: ClockConsts.ERR_BAD_DATE.format(rand_str) + '\n' + ClockConsts.ERR_BAD_TIME + .format(rand_str), rand_str + ' ' + new_time: ClockConsts.ERR_BAD_DATE.format(rand_str), new_date + ' ' + rand_str: ClockConsts.ERR_BAD_TIME.format(rand_str) } @@ -180,7 +182,8 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): with allure.step('Verify date'): logging.info('Verify date') - ClockUtils.verify_value(expected=show_clock_dict_before[ClockConsts.DATE], actual=show_clock_dict_after[ClockConsts.DATE]) + ClockUtils.verify_value(expected=show_clock_dict_before[ClockConsts.DATE], + actual=show_clock_dict_after[ClockConsts.DATE]) with allure.step('Verify time'): logging.info('Verify time') From e2e36ca990eb6df1fe6fad980cec96eac3440824 Mon Sep 17 00:00:00 2001 From: Alon Navarro Date: Thu, 22 Jun 2023 00:00:06 +0300 Subject: [PATCH 03/24] pre commit fixes --- tests/clock/ClockUtils.py | 2 +- tests/clock/test_clock.py | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/clock/ClockUtils.py b/tests/clock/ClockUtils.py index b1720fe031b..9319060c5a1 100755 --- a/tests/clock/ClockUtils.py +++ b/tests/clock/ClockUtils.py @@ -2,8 +2,8 @@ import random import datetime import allure -import pytest import time + from tests.common.helpers.assertions import pytest_assert from tests.clock.ClockConsts import ClockConsts from tests.common.errors import RunAnsibleModuleFail diff --git a/tests/clock/test_clock.py b/tests/clock/test_clock.py index 9449cf1232f..71ee2ffeecd 100755 --- a/tests/clock/test_clock.py +++ b/tests/clock/test_clock.py @@ -1,11 +1,9 @@ import logging import random import string - import pytest import allure -from datetime import datetime -from tests.common.helpers.assertions import pytest_assert + from tests.clock.ClockUtils import ClockUtils from tests.clock.ClockConsts import ClockConsts From 71dd779e741ec5524b5cb21a7b0ff9e4c87cbdf4 Mon Sep 17 00:00:00 2001 From: Alon Navarro Date: Thu, 11 May 2023 20:08:42 +0300 Subject: [PATCH 04/24] change to new string format --- tests/clock/ClockUtils.py | 168 +++++++++++++++++++------------------- tests/clock/conftest.py | 16 ++-- tests/clock/test_clock.py | 38 ++++----- 3 files changed, 111 insertions(+), 111 deletions(-) diff --git a/tests/clock/ClockUtils.py b/tests/clock/ClockUtils.py index 9319060c5a1..0e51ed8270f 100755 --- a/tests/clock/ClockUtils.py +++ b/tests/clock/ClockUtils.py @@ -14,16 +14,16 @@ class ClockUtils: def run_cmd(duthosts, cmd, param=''): """ @summary: - Run a given command and return it's output. - * a successful command returns empty output (''), while failure returns error message + Run a given command and return its output. + * A successful command returns an empty output (''), while failure returns an error message @return: commands output (str) """ - with allure.step('Run command: "{}" with param "{}"'.format(cmd, param)): - logging.info('Run command: "{}" with param "{}"'.format(cmd, param)) + with allure.step(f'Run command: "{cmd}" with param "{param}"'): + logging.info(f'Run command: "{cmd}" with param "{param}"') DUT_HOSTNAME = duthosts[0].hostname cmd_to_run = cmd if param == '' else cmd + ' ' + param - logging.info('Actual command to run: "{}"'.format(cmd_to_run)) + logging.info(f'Actual command to run: "{cmd_to_run}"') try: cmd_output = duthosts.command(cmd_to_run)[DUT_HOSTNAME][ClockConsts.STDOUT] @@ -31,15 +31,15 @@ def run_cmd(duthosts, cmd, param=''): output = cmd_err.results[ClockConsts.STDOUT] err = cmd_err.results[ClockConsts.STDERR] cmd_output = output if output else err - logging.info('Command Error!\nError message: "{}"'.format(cmd_output)) - logging.info('Output type: {}'.format(type(cmd_output))) - logging.info('Output: {}'.format(cmd_output)) + logging.info(f'Command Error!\nError message: "{cmd_output}"') + logging.info(f'Output type: {type(cmd_output)}') + logging.info(f'Output: {cmd_output}') with allure.step('Convert output to string'): logging.info('Convert output to string') cmd_output = str(cmd_output) - logging.info('Output type: {}'.format(type(cmd_output))) - logging.info('Output: {}'.format(cmd_output)) + logging.info(f'Output type: {type(cmd_output)}') + logging.info(f'Output: {cmd_output}') return cmd_output @staticmethod @@ -59,14 +59,14 @@ def parse_show_clock_output(show_clock_output): date = ' '.join(output_list[0:4]) time = ' '.join(output_list[4:6]) timezone = ' '.join(output_list[6:]) - logging.info('Splited output:\ndate: "{}"\ntime: "{}"\ntimezone: "{}"'.format(date, time, timezone)) + logging.info(f'Splited output:\ndate: "{date}"\ntime: "{time}"\ntimezone: "{timezone}"') res = { ClockConsts.DATE: date, ClockConsts.TIME: time, ClockConsts.TIMEZONE: timezone } - logging.info('res dict: {}'.format(res)) + logging.info(f'res dict: {res}') return res @@ -98,14 +98,14 @@ def parse_linux_cmd_output(linux_cmd_output): with allure.step('Parse linux command output into dictionary'): logging.info('Parse linux command output into dictionary') rows = [row.strip() for row in linux_cmd_output.split('\n')] # split by rows - logging.info('rows: {}'.format(rows)) + logging.info(f'rows: {rows}') res_dict = {} for row in rows: - logging.info('row: "{}"'.format(row)) + logging.info(f'row: "{row}"') idx = row.index(':') k, v = row[0: idx], row[idx + 2:] res_dict[k] = v - logging.info('Result dict:\n{}'.format(res_dict)) + logging.info(f'Result dict:\n{res_dict}') return res_dict @staticmethod @@ -115,14 +115,14 @@ def validate_date(date_str): Verify that given string is in a good date format: "Mon 03 Apr 2023" @param date_str: the given string """ - with allure.step('Validate date for: "{}"'.format(date_str)): - logging.info('Validate date for: "{}"'.format(date_str)) + with allure.step(f'Validate date for: "{date_str}"'): + logging.info(f'Validate date for: "{date_str}"') try: datetime.datetime.strptime(date_str, "%a %d %b %Y") logging.info('Validate date success') except ValueError: logging.info('Validate date fail') - pytest_assert(False, 'Given string "{}" is not a valid date'.format(date_str)) + pytest_assert(False, f'Given string "{date_str}" is not a valid date') @staticmethod def validate_time(time_str): @@ -131,14 +131,14 @@ def validate_time(time_str): Verify that given string is in a good time format: "11:29:46 AM" (or PM) @param time_str: the given string """ - with allure.step('Validate time for: "{}"'.format(time_str)): - logging.info('Validate time for: "{}"'.format(time_str)) + with allure.step(f'Validate time for: "{time_str}"'): + logging.info(f'Validate time for: "{time_str}"') try: datetime.datetime.strptime(time_str, "%I:%M:%S %p") logging.info('Validate time success') except ValueError: logging.info('Validate time fail') - pytest_assert(False, 'Given string "{}" is not a valid time'.format(time_str)) + pytest_assert(False, f'Given string "{time_str}" is not a valid time') @staticmethod def get_valid_timezones(duthosts): @@ -160,8 +160,8 @@ def validate_timezone(timezone_str, duthosts): @param timezone_str: the given string @param duthosts: duthosts """ - with allure.step('Verify that given string "{}" is a valid timezone'.format(timezone_str)): - logging.info('Verify that given string "{}" is a valid timezone'.format(timezone_str)) + with allure.step(f'Verify that given string "{timezone_str}" is a valid timezone'): + logging.info(f'Verify that given string "{timezone_str}" is a valid timezone') with allure.step('Get timezone from timedatectl linux command'): logging.info('Get timezone from timedatectl linux command') @@ -170,21 +170,19 @@ def validate_timezone(timezone_str, duthosts): timedatectl_timezone = timedatectl_output[ClockConsts.TIME_ZONE] timedatectl_tz_name = timedatectl_timezone.split()[0] timedatectl_tz_abbreviation = timedatectl_timezone.split(' ')[1].split(',')[0].replace('(', '') - logging.info('Timezone in timedatectl: "{}"\nTimezone name: "{}"\nTimezone abbreviation: "{}"' - .format(timedatectl_timezone, timedatectl_tz_name, timedatectl_tz_abbreviation)) + logging.info(f'Timezone in timedatectl: "{timedatectl_timezone}"\nTimezone name: ' + f'"{timedatectl_tz_name}"\nTimezone abbreviation: "{timedatectl_tz_abbreviation}" ') - with allure.step('Verify timezone name "{}" from timedatectl is in valid timezones' - .format(timedatectl_tz_name)): - logging.info('Verify timezone name "{}" from timedatectl is in valid timezones' - .format(timedatectl_tz_name)) + with allure.step(f'Verify timezone name "{timedatectl_tz_name}" from timedatectl is in valid timezones'): + logging.info(f'Verify timezone name "{timedatectl_tz_name}" from timedatectl is in valid timezones') valid_timezones = ClockUtils.get_valid_timezones(duthosts) pytest_assert(timedatectl_tz_name in valid_timezones, - 'Error: string "{}" is not in the valid timezones list'.format(timezone_str)) + f'Error: string "{timezone_str}" is not in the valid timezones list') - with allure.step('Verify that the given timezone "{}" equals to timezone abbreviation in timedatectl "{}"' - .format(timezone_str, timedatectl_tz_abbreviation)): - logging.info('Verify that the given timezone "{}" equals to timezone abbreviation in timedatectl "{}"' - .format(timezone_str, timedatectl_tz_abbreviation)) + with allure.step(f'Verify that the given timezone "{timezone_str}" equals to timezone abbreviation in ' + f'timedatectl "{timedatectl_tz_abbreviation}"'): + logging.info(f'Verify that the given timezone "{timezone_str}" equals to timezone abbreviation in ' + f'timedatectl "{timedatectl_tz_abbreviation}"') ClockUtils.verify_value(expected=timedatectl_tz_abbreviation, actual=timezone_str) @staticmethod @@ -194,24 +192,25 @@ def verify_value(expected, actual, should_be_equal=True): Asserts a given value is as expected @param expected: expected value @param actual: actual given value + @param should_be_equal: whether the values should be equal or not """ expected_to_print = "''" if expected == '' else expected actual_to_print = "''" if actual == '' else actual if should_be_equal: - with allure.step('Verify that actual value - {} is as expected - {}' - .format(expected_to_print, actual_to_print)): - logging.info('Verify that actual value - {} is as expected - {}' - .format(expected_to_print, actual_to_print)) - pytest_assert(actual == expected, 'Error: Values are not equal.\nExpected: {}\t{}\nActual: {}\t{}' - .format(expected_to_print, type(expected), actual_to_print, type(actual))) + with allure.step(f'Verify that actual value - {expected_to_print} is as expected - {actual_to_print}'): + logging.info(f'Verify that actual value - {expected_to_print} is as expected - {actual_to_print}') + pytest_assert(actual == expected, f'Error: Values are not equal.\n' + f'Expected: {expected_to_print}\t{type(expected)}\n' + f'Actual: {actual_to_print}\t{type(actual)}') else: - with allure.step('Verify that actual value - {} is different than expected - {}' - .format(expected_to_print, actual_to_print)): - logging.info('Verify that actual value - {} is different than expected - {}' - .format(expected_to_print, actual_to_print)) - pytest_assert(actual != expected, 'Error: Values are equal.\nExpected: {}\t{}\nActual: {}\t{}' - .format(expected_to_print, type(expected), actual_to_print, type(actual))) + with allure.step(f'Verify that actual value - {expected_to_print} ' + f'is different than expected - {actual_to_print}'): + logging.info(f'Verify that actual value - {expected_to_print} ' + f'is different than expected - {actual_to_print}') + pytest_assert(actual != expected, f'Error: Values are equal.\n' + f'Expected: {expected_to_print}\t{type(expected)}\n' + f'Actual: {actual_to_print}\t{type(actual)}') @staticmethod def verify_substring(expected_substr, whole_str): @@ -221,12 +220,12 @@ def verify_substring(expected_substr, whole_str): @param expected_substr: expected substring @param whole_str: the whole string """ - with allure.step('Verify that string "{}" contains the substring "{}"'.format(whole_str, expected_substr)): - logging.info('Verify that string "{}" contains the substring "{}"'.format(whole_str, expected_substr)) + with allure.step(f'Verify that string "{whole_str}" contains the substring "{expected_substr}"'): + logging.info(f'Verify that string "{whole_str}" contains the substring "{expected_substr}"') pytest_assert(expected_substr in whole_str, - 'Error: The given string does not contain the expected substring.\n' - 'Expected substring: "{}"\n' - 'Given (whole) string: "{}"'.format(expected_substr, whole_str)) + f'Error: The given string does not contain the expected substring.\n' + f'Expected substring: "{expected_substr}"\n' + f'Given (whole) string: "{whole_str}"') @ staticmethod def verify_command(cmd_output, should_succeed=True, expected_err=''): @@ -244,8 +243,8 @@ def verify_command(cmd_output, should_succeed=True, expected_err=''): logging.info('Verify that command succeeded') ClockUtils.verify_value(expected=ClockConsts.OUTPUT_CMD_SUCCESS, actual=cmd_output) else: - with allure.step('Verify that command failed and output contains "{}"'.format(expected_err)): - logging.info('Verify that command failed and output contains "{}"'.format(expected_err)) + with allure.step(f'Verify that command failed and output contains "{expected_err}"'): + logging.info(f'Verify that command failed and output contains "{expected_err}"') ClockUtils.verify_substring(expected_substr=expected_err, whole_str=cmd_output) @ staticmethod @@ -259,10 +258,10 @@ def verify_timezone_value(duthosts, tz_name, tz_abbreviation): @param tz_name: The expected timezone @param tz_abbreviation: The actual given timezone abbreviation """ - with allure.step('Verify that given timezone abbreviation "{}" matches to expected timezone "{}"' - .format(tz_abbreviation, tz_name)): - logging.info('Verify that given timezone abbreviation "{}" matches to expected timezone "{}"' - .format(tz_abbreviation, tz_name)) + with allure.step(f'Verify that given timezone abbreviation "{tz_abbreviation}" matches to ' + f'expected timezone "{tz_name}"'): + logging.info(f'Verify that given timezone abbreviation "{tz_abbreviation}" matches to ' + f'expected timezone "{tz_name}"') with allure.step('Get timezone details from timedatectl command'): logging.info('Get timezone details from timedatectl command') @@ -271,19 +270,20 @@ def verify_timezone_value(duthosts, tz_name, tz_abbreviation): timedatectl_timezone = timedatectl_output[ClockConsts.TIME_ZONE] timedatectl_tz_name = timedatectl_timezone.split()[0] timedatectl_tz_abbreviation = timedatectl_timezone.split(' ')[1].split(',')[0].replace('(', '') - logging.info('Timezone in timedatectl: "{}"\nTimezone name: "{}"\nTimezone abbreviation: "{}"' - .format(timedatectl_timezone, timedatectl_tz_name, timedatectl_tz_abbreviation)) - - with allure.step('Check that given timezone "{}" equals to timezone in timedatectl "{}"' - .format(tz_name, timedatectl_tz_name)): - logging.info('Check that given timezone "{}" equals to timezone in timedatectl "{}"' - .format(tz_name, timedatectl_tz_name)) + logging.info(f'Timezone in timedatectl: "{timedatectl_timezone}"\n' + f'Timezone name: "{timedatectl_tz_name}"\n' + f'Timezone abbreviation: "{timedatectl_tz_abbreviation}"') + + with allure.step(f'Check that given timezone "{tz_name}" equals to timezone in ' + f'timedatectl "{timedatectl_tz_name}"'): + logging.info(f'Check that given timezone "{tz_name}" equals to timezone in ' + f'timedatectl "{timedatectl_tz_name}"') ClockUtils.verify_value(expected=timedatectl_tz_name, actual=tz_name) - with allure.step('Check that given timezone abbreviation "{}" matches the expected timezone "{}"' - .format(tz_abbreviation, tz_name)): - logging.info('Check that given timezone abbreviation "{}" matches the expected timezone "{}"' - .format(tz_abbreviation, tz_name)) + with allure.step(f'Check that given timezone abbreviation "{tz_abbreviation}" ' + f'matches the expected timezone "{tz_name}"'): + logging.info(f'Check that given timezone abbreviation "{tz_abbreviation}" ' + f'matches the expected timezone "{tz_name}"') ClockUtils.verify_value(expected=timedatectl_tz_abbreviation, actual=tz_abbreviation) @ staticmethod @@ -306,7 +306,7 @@ def select_random_date(): rand_date_str = rand_date.strftime('%Y-%m-%d') - logging.info('Selected random date: "{}"'.format(rand_date_str)) + logging.info(f'Selected random date: "{rand_date_str}"') return rand_date_str @ staticmethod @@ -324,7 +324,7 @@ def select_random_time(): rand_time_str = time.strftime("%H:%M:%S", rand_time_obj) - logging.info('Selected random time: "{}"'.format(rand_time_str)) + logging.info(f'Selected random time: "{rand_time_str}"') return rand_time_str @ staticmethod @@ -336,10 +336,10 @@ def convert_show_clock_date(show_clock_date): @param show_clock_date: given date from show clock @return: converted date """ - with allure.step('Convert date "{}" to format "YYYY-MM-DD"'.format(show_clock_date)): - logging.info('Convert date "{}" to format "YYYY-MM-DD"'.format(show_clock_date)) + with allure.step(f'Convert date "{show_clock_date}" to format "YYYY-MM-DD"'): + logging.info(f'Convert date "{show_clock_date}" to format "YYYY-MM-DD"') converted_date = datetime.datetime.strptime(show_clock_date, "%a %d %b %Y").strftime("%Y-%m-%d") - logging.info('Converted date: "{}"'.format(converted_date)) + logging.info(f'Converted date: "{converted_date}"') return converted_date @ staticmethod @@ -351,10 +351,10 @@ def convert_show_clock_time(show_clock_time): @param show_clock_time: given time from show clock @return: converted me """ - with allure.step('Convert time "{}" to format "hh:mm:ss"'.format(show_clock_time)): - logging.info('Convert time "{}" to format "hh:mm:ss"'.format(show_clock_time)) + with allure.step(f'Convert time "{show_clock_time}" to format "hh:mm:ss"'): + logging.info(f'Convert time "{show_clock_time}" to format "hh:mm:ss"') converted_time = datetime.datetime.strptime(show_clock_time, "%I:%M:%S %p").strftime("%H:%M:%S") - logging.info('Converted time: "{}"'.format(converted_time)) + logging.info(f'Converted time: "{converted_time}"') return converted_time @ staticmethod @@ -367,18 +367,18 @@ def verify_time(expected, actual, allowed_margin=ClockConsts.TIME_MARGIN): @param actual: actual given time value @param allowed_margin: allowed margin between two times (in seconds) """ - with allure.step('Verify that diff between "{}" and "{}" (in seconds) is no longer than {}' - .format(expected, actual, allowed_margin)): - logging.info('Verify that diff between "{}" and "{}" (in seconds) is no longer than {}' - .format(expected, actual, allowed_margin)) + with allure.step(f'Verify that diff between "{expected}" and "{actual}" (in seconds) ' + f'is no longer than {allowed_margin}'): + logging.info(f'Verify that diff between "{expected}" and "{actual}" (in seconds) ' + f'is no longer than {allowed_margin}') - with allure.step('Calculate diff between "{}" and "{}" in seconds'.format(expected, actual)): - logging.info('Calculate diff between "{}" and "{}" in seconds'.format(expected, actual)) + with allure.step(f'Calculate diff between "{expected}" and "{actual}" in seconds'): + logging.info(f'Calculate diff between "{expected}" and "{actual}" in seconds') time_obj1 = datetime.datetime.strptime(expected, "%H:%M:%S") time_obj2 = datetime.datetime.strptime(actual, "%H:%M:%S") diff_seconds = abs((time_obj2 - time_obj1).total_seconds()) - with allure.step('Verify that actual diff {} is not larger than {}'.format(diff_seconds, allowed_margin)): - logging.info('Verify that actual diff {} is not larger than {}'.format(diff_seconds, allowed_margin)) + with allure.step(f'Verify that actual diff {diff_seconds} is not larger than {allowed_margin}'): + logging.info(f'Verify that actual diff {diff_seconds} is not larger than {allowed_margin}') ClockUtils.verify_value(True, diff_seconds <= allowed_margin) diff --git a/tests/clock/conftest.py b/tests/clock/conftest.py index df09ad2ec8a..75fb6fd01fe 100755 --- a/tests/clock/conftest.py +++ b/tests/clock/conftest.py @@ -17,7 +17,7 @@ def ntp_server(request): @summary: Return NTP server's ip if given, otherwise skip the test """ ntp_server_ip = request.config.getoption("ntp_server") - logging.info('NTP server ip from execution parameter: {}'.format(ntp_server_ip)) + logging.info(f'NTP server ip from execution parameter: {ntp_server_ip}') if ntp_server_ip is None: logging.info('IP of NTP server was not given, will not run the test') pytest.skip("IP of NTP server was not given, will not run the test") @@ -30,12 +30,12 @@ def init_timezone(duthosts): @summary: fixture to init timezone before and after each test """ - logging.info('Set timezone to {} before test'.format(ClockConsts.TEST_TIMEZONE)) + logging.info(f'Set timezone to {ClockConsts.TEST_TIMEZONE} before test') ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, ClockConsts.TEST_TIMEZONE) yield - logging.info('Set timezone to {} after test'.format(ClockConsts.TEST_TIMEZONE)) + logging.info(f'Set timezone to {ClockConsts.TEST_TIMEZONE} after test') ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, ClockConsts.TEST_TIMEZONE) @@ -49,7 +49,7 @@ def restore_time(duthosts, ntp_server): logging.info('Reset time after test. Sync with NTP server: {}') - logging.info('Sync with NTP server: {}'.format(ntp_server)) + logging.info(f'Sync with NTP server: {ntp_server}') ClockUtils.verify_substring(ClockConsts.OUTPUT_CMD_NTP_ADD_SUCCESS.format(ntp_server), ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_NTP_ADD, ntp_server)) @@ -59,14 +59,14 @@ def restore_time(duthosts, ntp_server): if match: polling_time_seconds = int(match.group(1)) else: - logging.info('Could not match the regex.\nPattern: "{}"\nShow ntp output string: "{}"' - .format(ClockConsts.REGEX_NTP_POLLING_TIME, show_ntp_output)) + logging.info(f'Could not match the regex.\n' + f'Pattern: "{ClockConsts.REGEX_NTP_POLLING_TIME}"\nShow ntp output string: "{show_ntp_output}"') polling_time_seconds = ClockConsts.RANDOM_NUM - logging.info('Polling time (in seconds): {}'.format(polling_time_seconds + 1)) + logging.info(f'Polling time (in seconds): {polling_time_seconds + 1}') logging.info('Wait for the sync') time.sleep(polling_time_seconds) - logging.info('Delete NTP server: {}'.format(ntp_server)) + logging.info(f'Delete NTP server: {ntp_server}') ClockUtils.verify_substring(ClockConsts.OUTPUT_CMD_NTP_DEL_SUCCESS.format(ntp_server), ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_NTP_DEL, ntp_server)) diff --git a/tests/clock/test_clock.py b/tests/clock/test_clock.py index 71ee2ffeecd..b0f352687aa 100755 --- a/tests/clock/test_clock.py +++ b/tests/clock/test_clock.py @@ -58,16 +58,16 @@ def test_config_clock_timezone(duthosts, init_timezone): while new_timezone == orig_timezone: new_timezone = random.choice(valid_timezones) - with allure.step('Set the new timezone "{}"'.format(new_timezone)): - logging.info('Set the new timezone "{}"'.format(new_timezone)) + with allure.step(f'Set the new timezone "{new_timezone}"'): + logging.info(f'Set the new timezone "{new_timezone}"') output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, new_timezone) with allure.step('Verify command success'): logging.info('Verify command success') ClockUtils.verify_command(cmd_output=output, should_succeed=True) - with allure.step('Verify timezone changed to "{}"'.format(new_timezone)): - logging.info('Verify timezone changed to "{}"'.format(new_timezone)) + with allure.step(f'Verify timezone changed to "{new_timezone}"'): + logging.info(f'Verify timezone changed to "{new_timezone}"') cur_timezone = ClockUtils \ .parse_show_clock_output(ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK))[ClockConsts.TIMEZONE] ClockUtils.verify_timezone_value(duthosts, tz_name=new_timezone, tz_abbreviation=cur_timezone) @@ -77,10 +77,10 @@ def test_config_clock_timezone(duthosts, init_timezone): invalid_timezone = ''.join(random.choice(string.ascii_lowercase) for _ in range(random.randint(1, 10))) while invalid_timezone in valid_timezones: invalid_timezone = ''.join(random.choice(string.ascii_lowercase) for _ in range(random.randint(1, 10))) - logging.info('Selected invalid timezone: "{}"'.format(invalid_timezone)) + logging.info(f'Selected invalid timezone: "{invalid_timezone}"') - with allure.step('Try to set the invalid timezone "{}"'.format(invalid_timezone)): - logging.info('Try to set the invalid timezone "{}"'.format(invalid_timezone)) + with allure.step(f'Try to set the invalid timezone "{invalid_timezone}"'): + logging.info(f'Try to set the invalid timezone "{invalid_timezone}"') output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, invalid_timezone) with allure.step('Verify command failure'): @@ -112,16 +112,16 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): new_time = ClockUtils.select_random_time() new_datetime = new_date + ' ' + new_time - with allure.step('Set new date and time "{}"'.format(new_datetime)): - logging.info('Set new date and time "{}"'.format(new_datetime)) + with allure.step(f'Set new date and time "{new_datetime}"'): + logging.info(f'Set new date and time "{new_datetime}"') output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_DATE, new_datetime) with allure.step('Verify command success'): logging.info('Verify command success') ClockUtils.verify_command(cmd_output=output, should_succeed=True) - with allure.step('Verify date and time changed to "{}"'.format(new_datetime)): - logging.info('Verify date and time changed to "{}"'.format(new_datetime)) + with allure.step(f'Verify date and time changed to "{new_datetime}"'): + logging.info(f'Verify date and time changed to "{new_datetime}"') with allure.step('Get datetime from show clock'): logging.info('Get datetime from show clock') show_clock_output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) @@ -140,29 +140,29 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): with allure.step('Select random string as invalid input'): logging.info('Select random string as invalid input') rand_str = ''.join(random.choice(string.ascii_lowercase) for i in range(ClockConsts.RANDOM_NUM)) - logging.info('Selected random string: "{}"'.format(rand_str)) + logging.info(f'Selected random string: "{rand_str}"') with allure.step('Try to set invalid inputs'): logging.info('Try to set invalid inputs') errors = { '': ClockConsts.ERR_MISSING_DATE, rand_str: ClockConsts.ERR_MISSING_TIME, - rand_str + ' ' + rand_str: ClockConsts.ERR_BAD_DATE.format(rand_str) + '\n' + ClockConsts.ERR_BAD_TIME - .format(rand_str), + rand_str + ' ' + rand_str: ClockConsts.ERR_BAD_DATE.format(rand_str) + '\n' + + ClockConsts.ERR_BAD_TIME.format(rand_str), rand_str + ' ' + new_time: ClockConsts.ERR_BAD_DATE.format(rand_str), new_date + ' ' + rand_str: ClockConsts.ERR_BAD_TIME.format(rand_str) } i = 0 for invalid_input, err_msg in errors.items(): - logging.info('Invalid input #{}: "{}"\nExpected error:\n{}'.format(i, invalid_input, err_msg)) + logging.info(f'Invalid input #{i}: "{invalid_input}"\nExpected error:\n{err_msg}') with allure.step('Get show clock output before running the config command'): logging.info('Get show clock output before running the config command') show_clock_output_before = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) - with allure.step('Try to set "{}"'.format(invalid_input)): - logging.info('Try to set "{}"'.format(invalid_input)) + with allure.step(f'Try to set "{invalid_input}"'): + logging.info(f'Try to set "{invalid_input}"') output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_DATE, invalid_input) with allure.step('Get show clock output after running the config command'): @@ -173,8 +173,8 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): logging.info('Verify command failure') ClockUtils.verify_command(cmd_output=output, should_succeed=False, expected_err=err_msg) - with allure.step('Verify date and time have not changed (still "{}")'.format(new_datetime)): - logging.info('Verify date and time have not changed (still "{}")'.format(new_datetime)) + with allure.step(f'Verify date and time have not changed (still "{new_datetime}")'): + logging.info(f'Verify date and time have not changed (still "{new_datetime}")') show_clock_dict_before = ClockUtils.parse_show_clock_output(show_clock_output_before) show_clock_dict_after = ClockUtils.parse_show_clock_output(show_clock_output_after) From 94110835672ee2e474f0b604c581452847fd2785 Mon Sep 17 00:00:00 2001 From: Alon Navarro Date: Thu, 11 May 2023 20:23:47 +0300 Subject: [PATCH 05/24] comment typo fix --- tests/clock/test_clock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/clock/test_clock.py b/tests/clock/test_clock.py index b0f352687aa..5d457637730 100755 --- a/tests/clock/test_clock.py +++ b/tests/clock/test_clock.py @@ -98,7 +98,7 @@ def test_config_clock_timezone(duthosts, init_timezone): def test_config_clock_date(duthosts, init_timezone, restore_time): """ @summary: - Check that 'config clock ate' command works correctly + Check that 'config clock date' command works correctly Steps: 1. Set a new valid date and time using the command From e55f7d98912c70108cda28bbf3bab3f39d7d4d3f Mon Sep 17 00:00:00 2001 From: Alon Navarro Date: Wed, 17 May 2023 12:40:51 +0300 Subject: [PATCH 06/24] wrap allure step context in a context manager function --- tests/clock/ClockUtils.py | 105 ++++++++++++++++---------------------- tests/clock/conftest.py | 6 +-- tests/clock/test_clock.py | 80 ++++++++++------------------- 3 files changed, 75 insertions(+), 116 deletions(-) diff --git a/tests/clock/ClockUtils.py b/tests/clock/ClockUtils.py index 0e51ed8270f..d76028de13d 100755 --- a/tests/clock/ClockUtils.py +++ b/tests/clock/ClockUtils.py @@ -1,6 +1,8 @@ import logging import random import datetime +from contextlib import contextmanager + import allure import time @@ -9,6 +11,21 @@ from tests.common.errors import RunAnsibleModuleFail +@contextmanager +def allure_step(step_msg): + """ + @summary: + Context manager that wraps allure step context and a log with the same message + @param step_msg: The desired step message + """ + with allure.step(step_msg) as allure_step_context: + logging.info(f'Step start: {step_msg}') + try: + yield allure_step_context + finally: + logging.info(f'Step end: {step_msg}') + + class ClockUtils: @staticmethod def run_cmd(duthosts, cmd, param=''): @@ -18,8 +35,7 @@ def run_cmd(duthosts, cmd, param=''): * A successful command returns an empty output (''), while failure returns an error message @return: commands output (str) """ - with allure.step(f'Run command: "{cmd}" with param "{param}"'): - logging.info(f'Run command: "{cmd}" with param "{param}"') + with allure_step(f'Run command: "{cmd}" with param "{param}"'): DUT_HOSTNAME = duthosts[0].hostname cmd_to_run = cmd if param == '' else cmd + ' ' + param @@ -32,14 +48,15 @@ def run_cmd(duthosts, cmd, param=''): err = cmd_err.results[ClockConsts.STDERR] cmd_output = output if output else err logging.info(f'Command Error!\nError message: "{cmd_output}"') + logging.info(f'Output type: {type(cmd_output)}') logging.info(f'Output: {cmd_output}') - with allure.step('Convert output to string'): logging.info('Convert output to string') cmd_output = str(cmd_output) logging.info(f'Output type: {type(cmd_output)}') logging.info(f'Output: {cmd_output}') + return cmd_output @staticmethod @@ -53,8 +70,7 @@ def parse_show_clock_output(show_clock_output): @param show_clock_output: the given show clock output @return: The splited output as a dict """ - with allure.step('Split output of show clock'): - logging.info('Split output of show clock') + with allure_step('Split output of show clock'): output_list = show_clock_output.split(' ') date = ' '.join(output_list[0:4]) time = ' '.join(output_list[4:6]) @@ -95,8 +111,7 @@ def parse_linux_cmd_output(linux_cmd_output): @param linux_cmd_output: given output of a linux command (str) @return: dictionary as mentioned in the example """ - with allure.step('Parse linux command output into dictionary'): - logging.info('Parse linux command output into dictionary') + with allure_step('Parse linux command output into dictionary'): rows = [row.strip() for row in linux_cmd_output.split('\n')] # split by rows logging.info(f'rows: {rows}') res_dict = {} @@ -115,8 +130,7 @@ def validate_date(date_str): Verify that given string is in a good date format: "Mon 03 Apr 2023" @param date_str: the given string """ - with allure.step(f'Validate date for: "{date_str}"'): - logging.info(f'Validate date for: "{date_str}"') + with allure_step(f'Validate date for: "{date_str}"'): try: datetime.datetime.strptime(date_str, "%a %d %b %Y") logging.info('Validate date success') @@ -131,8 +145,7 @@ def validate_time(time_str): Verify that given string is in a good time format: "11:29:46 AM" (or PM) @param time_str: the given string """ - with allure.step(f'Validate time for: "{time_str}"'): - logging.info(f'Validate time for: "{time_str}"') + with allure_step(f'Validate time for: "{time_str}"'): try: datetime.datetime.strptime(time_str, "%I:%M:%S %p") logging.info('Validate time success') @@ -148,8 +161,7 @@ def get_valid_timezones(duthosts): @param duthosts: duthosts object @return: list of timezones (strings) """ - with allure.step('Get list of valid timezones from show clock timezones command'): - logging.info('Get list of valid timezones from show clock timezones command') + with allure_step('Get list of valid timezones from show clock timezones command'): return ClockUtils.run_cmd(duthosts=duthosts, cmd=ClockConsts.CMD_SHOW_CLOCK_TIMEZONES).split() @staticmethod @@ -160,11 +172,8 @@ def validate_timezone(timezone_str, duthosts): @param timezone_str: the given string @param duthosts: duthosts """ - with allure.step(f'Verify that given string "{timezone_str}" is a valid timezone'): - logging.info(f'Verify that given string "{timezone_str}" is a valid timezone') - - with allure.step('Get timezone from timedatectl linux command'): - logging.info('Get timezone from timedatectl linux command') + with allure_step(f'Verify that given string "{timezone_str}" is a valid timezone'): + with allure_step('Get timezone from timedatectl linux command'): timedatectl_output = \ ClockUtils.parse_linux_cmd_output(ClockUtils.run_cmd(duthosts, ClockConsts.CMD_TIMEDATECTL)) timedatectl_timezone = timedatectl_output[ClockConsts.TIME_ZONE] @@ -173,16 +182,13 @@ def validate_timezone(timezone_str, duthosts): logging.info(f'Timezone in timedatectl: "{timedatectl_timezone}"\nTimezone name: ' f'"{timedatectl_tz_name}"\nTimezone abbreviation: "{timedatectl_tz_abbreviation}" ') - with allure.step(f'Verify timezone name "{timedatectl_tz_name}" from timedatectl is in valid timezones'): - logging.info(f'Verify timezone name "{timedatectl_tz_name}" from timedatectl is in valid timezones') + with allure_step(f'Verify timezone name "{timedatectl_tz_name}" from timedatectl is in valid timezones'): valid_timezones = ClockUtils.get_valid_timezones(duthosts) pytest_assert(timedatectl_tz_name in valid_timezones, f'Error: string "{timezone_str}" is not in the valid timezones list') - with allure.step(f'Verify that the given timezone "{timezone_str}" equals to timezone abbreviation in ' + with allure_step(f'Verify that the given timezone "{timezone_str}" equals to timezone abbreviation in ' f'timedatectl "{timedatectl_tz_abbreviation}"'): - logging.info(f'Verify that the given timezone "{timezone_str}" equals to timezone abbreviation in ' - f'timedatectl "{timedatectl_tz_abbreviation}"') ClockUtils.verify_value(expected=timedatectl_tz_abbreviation, actual=timezone_str) @staticmethod @@ -198,16 +204,13 @@ def verify_value(expected, actual, should_be_equal=True): actual_to_print = "''" if actual == '' else actual if should_be_equal: - with allure.step(f'Verify that actual value - {expected_to_print} is as expected - {actual_to_print}'): - logging.info(f'Verify that actual value - {expected_to_print} is as expected - {actual_to_print}') + with allure_step(f'Verify that actual value - {expected_to_print} is as expected - {actual_to_print}'): pytest_assert(actual == expected, f'Error: Values are not equal.\n' f'Expected: {expected_to_print}\t{type(expected)}\n' f'Actual: {actual_to_print}\t{type(actual)}') else: - with allure.step(f'Verify that actual value - {expected_to_print} ' + with allure_step(f'Verify that actual value - {expected_to_print} ' f'is different than expected - {actual_to_print}'): - logging.info(f'Verify that actual value - {expected_to_print} ' - f'is different than expected - {actual_to_print}') pytest_assert(actual != expected, f'Error: Values are equal.\n' f'Expected: {expected_to_print}\t{type(expected)}\n' f'Actual: {actual_to_print}\t{type(actual)}') @@ -220,8 +223,7 @@ def verify_substring(expected_substr, whole_str): @param expected_substr: expected substring @param whole_str: the whole string """ - with allure.step(f'Verify that string "{whole_str}" contains the substring "{expected_substr}"'): - logging.info(f'Verify that string "{whole_str}" contains the substring "{expected_substr}"') + with allure_step(f'Verify that string "{whole_str}" contains the substring "{expected_substr}"'): pytest_assert(expected_substr in whole_str, f'Error: The given string does not contain the expected substring.\n' f'Expected substring: "{expected_substr}"\n' @@ -239,12 +241,10 @@ def verify_command(cmd_output, should_succeed=True, expected_err=''): @param expected_err: expected error message """ if should_succeed: - with allure.step('Verify that command succeeded'): - logging.info('Verify that command succeeded') + with allure_step('Verify that command succeeded'): ClockUtils.verify_value(expected=ClockConsts.OUTPUT_CMD_SUCCESS, actual=cmd_output) else: - with allure.step(f'Verify that command failed and output contains "{expected_err}"'): - logging.info(f'Verify that command failed and output contains "{expected_err}"') + with allure_step(f'Verify that command failed and output contains "{expected_err}"'): ClockUtils.verify_substring(expected_substr=expected_err, whole_str=cmd_output) @ staticmethod @@ -258,13 +258,10 @@ def verify_timezone_value(duthosts, tz_name, tz_abbreviation): @param tz_name: The expected timezone @param tz_abbreviation: The actual given timezone abbreviation """ - with allure.step(f'Verify that given timezone abbreviation "{tz_abbreviation}" matches to ' + with allure_step(f'Verify that given timezone abbreviation "{tz_abbreviation}" matches to ' f'expected timezone "{tz_name}"'): - logging.info(f'Verify that given timezone abbreviation "{tz_abbreviation}" matches to ' - f'expected timezone "{tz_name}"') - with allure.step('Get timezone details from timedatectl command'): - logging.info('Get timezone details from timedatectl command') + with allure_step('Get timezone details from timedatectl command'): timedatectl_output = \ ClockUtils.parse_linux_cmd_output(ClockUtils.run_cmd(duthosts, ClockConsts.CMD_TIMEDATECTL)) timedatectl_timezone = timedatectl_output[ClockConsts.TIME_ZONE] @@ -274,16 +271,12 @@ def verify_timezone_value(duthosts, tz_name, tz_abbreviation): f'Timezone name: "{timedatectl_tz_name}"\n' f'Timezone abbreviation: "{timedatectl_tz_abbreviation}"') - with allure.step(f'Check that given timezone "{tz_name}" equals to timezone in ' + with allure_step(f'Check that given timezone "{tz_name}" equals to timezone in ' f'timedatectl "{timedatectl_tz_name}"'): - logging.info(f'Check that given timezone "{tz_name}" equals to timezone in ' - f'timedatectl "{timedatectl_tz_name}"') ClockUtils.verify_value(expected=timedatectl_tz_name, actual=tz_name) - with allure.step(f'Check that given timezone abbreviation "{tz_abbreviation}" ' + with allure_step(f'Check that given timezone abbreviation "{tz_abbreviation}" ' f'matches the expected timezone "{tz_name}"'): - logging.info(f'Check that given timezone abbreviation "{tz_abbreviation}" ' - f'matches the expected timezone "{tz_name}"') ClockUtils.verify_value(expected=timedatectl_tz_abbreviation, actual=tz_abbreviation) @ staticmethod @@ -293,8 +286,7 @@ def select_random_date(): Select a random date @return: a random date as string in the format "YYYY-MM-DD" """ - with allure.step('Select a random date'): - logging.info('Select a random date') + with allure_step('Select a random date'): start_date = datetime.date.fromisoformat(ClockConsts.MIN_SYSTEM_DATE) end_date = datetime.date.fromisoformat(ClockConsts.MAX_SYSTEM_DATE) @@ -316,8 +308,7 @@ def select_random_time(): Select a random time @return: a random date as string in the format "hh:mm:ss" """ - with allure.step('Select a random time in a day'): - logging.info('Select a random time in a day') + with allure_step('Select a random time in a day'): rand_num_of_seconds_since_00 = random.randint(0, 24 * 60 * 60 - 1) rand_time_obj = time.gmtime(rand_num_of_seconds_since_00) @@ -336,8 +327,7 @@ def convert_show_clock_date(show_clock_date): @param show_clock_date: given date from show clock @return: converted date """ - with allure.step(f'Convert date "{show_clock_date}" to format "YYYY-MM-DD"'): - logging.info(f'Convert date "{show_clock_date}" to format "YYYY-MM-DD"') + with allure_step(f'Convert date "{show_clock_date}" to format "YYYY-MM-DD"'): converted_date = datetime.datetime.strptime(show_clock_date, "%a %d %b %Y").strftime("%Y-%m-%d") logging.info(f'Converted date: "{converted_date}"') return converted_date @@ -351,8 +341,7 @@ def convert_show_clock_time(show_clock_time): @param show_clock_time: given time from show clock @return: converted me """ - with allure.step(f'Convert time "{show_clock_time}" to format "hh:mm:ss"'): - logging.info(f'Convert time "{show_clock_time}" to format "hh:mm:ss"') + with allure_step(f'Convert time "{show_clock_time}" to format "hh:mm:ss"'): converted_time = datetime.datetime.strptime(show_clock_time, "%I:%M:%S %p").strftime("%H:%M:%S") logging.info(f'Converted time: "{converted_time}"') return converted_time @@ -367,18 +356,14 @@ def verify_time(expected, actual, allowed_margin=ClockConsts.TIME_MARGIN): @param actual: actual given time value @param allowed_margin: allowed margin between two times (in seconds) """ - with allure.step(f'Verify that diff between "{expected}" and "{actual}" (in seconds) ' + with allure_step(f'Verify that diff between "{expected}" and "{actual}" (in seconds) ' f'is no longer than {allowed_margin}'): - logging.info(f'Verify that diff between "{expected}" and "{actual}" (in seconds) ' - f'is no longer than {allowed_margin}') - with allure.step(f'Calculate diff between "{expected}" and "{actual}" in seconds'): - logging.info(f'Calculate diff between "{expected}" and "{actual}" in seconds') + with allure_step(f'Calculate diff between "{expected}" and "{actual}" in seconds'): time_obj1 = datetime.datetime.strptime(expected, "%H:%M:%S") time_obj2 = datetime.datetime.strptime(actual, "%H:%M:%S") diff_seconds = abs((time_obj2 - time_obj1).total_seconds()) - with allure.step(f'Verify that actual diff {diff_seconds} is not larger than {allowed_margin}'): - logging.info(f'Verify that actual diff {diff_seconds} is not larger than {allowed_margin}') + with allure_step(f'Verify that actual diff {diff_seconds} is not larger than {allowed_margin}'): ClockUtils.verify_value(True, diff_seconds <= allowed_margin) diff --git a/tests/clock/conftest.py b/tests/clock/conftest.py index 75fb6fd01fe..10fa094616b 100755 --- a/tests/clock/conftest.py +++ b/tests/clock/conftest.py @@ -19,8 +19,8 @@ def ntp_server(request): ntp_server_ip = request.config.getoption("ntp_server") logging.info(f'NTP server ip from execution parameter: {ntp_server_ip}') if ntp_server_ip is None: - logging.info('IP of NTP server was not given, will not run the test') - pytest.skip("IP of NTP server was not given, will not run the test") + logging.info('IP of NTP server was not given. Skipping the test') + pytest.skip("IP of NTP server was not given. Skipping the test") return ntp_server_ip @@ -47,7 +47,7 @@ def restore_time(duthosts, ntp_server): yield - logging.info('Reset time after test. Sync with NTP server: {}') + logging.info(f'Reset time after test. Sync with NTP server: {ntp_server}') logging.info(f'Sync with NTP server: {ntp_server}') ClockUtils.verify_substring(ClockConsts.OUTPUT_CMD_NTP_ADD_SUCCESS.format(ntp_server), diff --git a/tests/clock/test_clock.py b/tests/clock/test_clock.py index 5d457637730..ebd651edd3c 100755 --- a/tests/clock/test_clock.py +++ b/tests/clock/test_clock.py @@ -4,7 +4,7 @@ import pytest import allure -from tests.clock.ClockUtils import ClockUtils +from tests.clock.ClockUtils import ClockUtils, allure_step from tests.clock.ClockConsts import ClockConsts pytestmark = [ @@ -25,12 +25,10 @@ def test_show_clock(duthosts, init_timezone): 1. Run show clock 2. Validate info """ - with allure.step('Run show clock command'): - logging.info('Run show clock command') + with allure_step('Run show clock command'): show_clock_output = ClockUtils.run_cmd(duthosts=duthosts, cmd=ClockConsts.CMD_SHOW_CLOCK) - with allure.step('Verify info is valid'): - logging.info('Verify info is valid') + with allure_step('Verify info is valid'): output_dict = ClockUtils.parse_show_clock_output(show_clock_output) ClockUtils.validate_date(output_dict[ClockConsts.DATE]) ClockUtils.validate_time(output_dict[ClockConsts.TIME]) @@ -52,44 +50,36 @@ def test_config_clock_timezone(duthosts, init_timezone): orig_timezone = ClockUtils \ .parse_show_clock_output(ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK))[ClockConsts.TIMEZONE] - with allure.step('Select a random new valid timezone'): - logging.info('Select a random new valid timezone') + with allure_step('Select a random new valid timezone'): new_timezone = random.choice(valid_timezones) while new_timezone == orig_timezone: new_timezone = random.choice(valid_timezones) - with allure.step(f'Set the new timezone "{new_timezone}"'): - logging.info(f'Set the new timezone "{new_timezone}"') + with allure_step(f'Set the new timezone "{new_timezone}"'): output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, new_timezone) - with allure.step('Verify command success'): - logging.info('Verify command success') + with allure_step('Verify command success'): ClockUtils.verify_command(cmd_output=output, should_succeed=True) - with allure.step(f'Verify timezone changed to "{new_timezone}"'): - logging.info(f'Verify timezone changed to "{new_timezone}"') + with allure_step(f'Verify timezone changed to "{new_timezone}"'): cur_timezone = ClockUtils \ .parse_show_clock_output(ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK))[ClockConsts.TIMEZONE] ClockUtils.verify_timezone_value(duthosts, tz_name=new_timezone, tz_abbreviation=cur_timezone) - with allure.step('Select a random string as invalid timezone'): - logging.info('Select a random string as invalid timezone') + with allure_step('Select a random string as invalid timezone'): invalid_timezone = ''.join(random.choice(string.ascii_lowercase) for _ in range(random.randint(1, 10))) while invalid_timezone in valid_timezones: invalid_timezone = ''.join(random.choice(string.ascii_lowercase) for _ in range(random.randint(1, 10))) logging.info(f'Selected invalid timezone: "{invalid_timezone}"') - with allure.step(f'Try to set the invalid timezone "{invalid_timezone}"'): - logging.info(f'Try to set the invalid timezone "{invalid_timezone}"') + with allure_step(f'Try to set the invalid timezone "{invalid_timezone}"'): output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, invalid_timezone) - with allure.step('Verify command failure'): - logging.info('Verify command failure') + with allure_step('Verify command failure'): ClockUtils.verify_command(cmd_output=output, should_succeed=False, expected_err=ClockConsts.ERR_BAD_TIMEZONE .format(invalid_timezone)) - with allure.step('Verify timezone has not changed'): - logging.info('Verify timezone has not changed') + with allure_step('Verify timezone has not changed'): cur_timezone = ClockUtils \ .parse_show_clock_output(ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK))[ClockConsts.TIMEZONE] ClockUtils.verify_timezone_value(duthosts, tz_name=new_timezone, tz_abbreviation=cur_timezone) @@ -106,44 +96,35 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): 3. Try to set invalid date and time 4. Verify error and that time hasn't changed """ - with allure.step('Select valid date and time to set'): - logging.info('Select valid date and time to set') + with allure_step('Select valid date and time to set'): new_date = ClockUtils.select_random_date() new_time = ClockUtils.select_random_time() new_datetime = new_date + ' ' + new_time - with allure.step(f'Set new date and time "{new_datetime}"'): - logging.info(f'Set new date and time "{new_datetime}"') + with allure_step(f'Set new date and time "{new_datetime}"'): output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_DATE, new_datetime) - with allure.step('Verify command success'): - logging.info('Verify command success') + with allure_step('Verify command success'): ClockUtils.verify_command(cmd_output=output, should_succeed=True) - with allure.step(f'Verify date and time changed to "{new_datetime}"'): - logging.info(f'Verify date and time changed to "{new_datetime}"') - with allure.step('Get datetime from show clock'): - logging.info('Get datetime from show clock') + with allure_step(f'Verify date and time changed to "{new_datetime}"'): + with allure_step('Get datetime from show clock'): show_clock_output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) show_clock_dict = ClockUtils.parse_show_clock_output(show_clock_output) - with allure.step('Verify date'): - logging.info('Verify date') + with allure_step('Verify date'): cur_date = ClockUtils.convert_show_clock_date(show_clock_dict[ClockConsts.DATE]) ClockUtils.verify_value(expected=new_date, actual=cur_date) - with allure.step('Verify time'): - logging.info('Verify time') + with allure_step('Verify time'): cur_time = ClockUtils.convert_show_clock_time(show_clock_dict[ClockConsts.TIME]) ClockUtils.verify_time(expected=new_time, actual=cur_time) - with allure.step('Select random string as invalid input'): - logging.info('Select random string as invalid input') + with allure_step('Select random string as invalid input'): rand_str = ''.join(random.choice(string.ascii_lowercase) for i in range(ClockConsts.RANDOM_NUM)) logging.info(f'Selected random string: "{rand_str}"') - with allure.step('Try to set invalid inputs'): - logging.info('Try to set invalid inputs') + with allure_step('Try to set invalid inputs'): errors = { '': ClockConsts.ERR_MISSING_DATE, rand_str: ClockConsts.ERR_MISSING_TIME, @@ -157,34 +138,27 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): for invalid_input, err_msg in errors.items(): logging.info(f'Invalid input #{i}: "{invalid_input}"\nExpected error:\n{err_msg}') - with allure.step('Get show clock output before running the config command'): - logging.info('Get show clock output before running the config command') + with allure_step('Get show clock output before running the config command'): show_clock_output_before = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) - with allure.step(f'Try to set "{invalid_input}"'): - logging.info(f'Try to set "{invalid_input}"') + with allure_step(f'Try to set "{invalid_input}"'): output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_DATE, invalid_input) - with allure.step('Get show clock output after running the config command'): - logging.info('Get show clock output after running the config command') + with allure_step('Get show clock output after running the config command'): show_clock_output_after = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) - with allure.step('Verify command failure'): - logging.info('Verify command failure') + with allure_step('Verify command failure'): ClockUtils.verify_command(cmd_output=output, should_succeed=False, expected_err=err_msg) - with allure.step(f'Verify date and time have not changed (still "{new_datetime}")'): - logging.info(f'Verify date and time have not changed (still "{new_datetime}")') + with allure_step(f'Verify date and time have not changed (still "{new_datetime}")'): show_clock_dict_before = ClockUtils.parse_show_clock_output(show_clock_output_before) show_clock_dict_after = ClockUtils.parse_show_clock_output(show_clock_output_after) - with allure.step('Verify date'): - logging.info('Verify date') + with allure_step('Verify date'): ClockUtils.verify_value(expected=show_clock_dict_before[ClockConsts.DATE], actual=show_clock_dict_after[ClockConsts.DATE]) - with allure.step('Verify time'): - logging.info('Verify time') + with allure_step('Verify time'): time_before = ClockUtils.convert_show_clock_time(show_clock_dict_before[ClockConsts.TIME]) time_after = ClockUtils.convert_show_clock_time(show_clock_dict_after[ClockConsts.TIME]) ClockUtils.verify_time(expected=time_before, actual=time_after) From 8d0ffda5502cae2c82605110e2ac8d368bb7bd76 Mon Sep 17 00:00:00 2001 From: Alon Navarro Date: Wed, 17 May 2023 16:23:12 +0300 Subject: [PATCH 07/24] compare dates and times as date-time objects to handle midnight corner case --- tests/clock/ClockUtils.py | 51 +++++++++++++++++++++++++-------------- tests/clock/test_clock.py | 45 ++++++++++++++++++++++------------ 2 files changed, 63 insertions(+), 33 deletions(-) diff --git a/tests/clock/ClockUtils.py b/tests/clock/ClockUtils.py index d76028de13d..fce3c1c3fa0 100755 --- a/tests/clock/ClockUtils.py +++ b/tests/clock/ClockUtils.py @@ -32,7 +32,8 @@ def run_cmd(duthosts, cmd, param=''): """ @summary: Run a given command and return its output. - * A successful command returns an empty output (''), while failure returns an error message + * A successful command returns an empty output (except for show commands), + while failure returns an error message @return: commands output (str) """ with allure_step(f'Run command: "{cmd}" with param "{param}"'): @@ -49,14 +50,10 @@ def run_cmd(duthosts, cmd, param=''): cmd_output = output if output else err logging.info(f'Command Error!\nError message: "{cmd_output}"') - logging.info(f'Output type: {type(cmd_output)}') - logging.info(f'Output: {cmd_output}') - logging.info('Convert output to string') cmd_output = str(cmd_output) - logging.info(f'Output type: {type(cmd_output)}') logging.info(f'Output: {cmd_output}') - + return cmd_output @staticmethod @@ -117,9 +114,8 @@ def parse_linux_cmd_output(linux_cmd_output): res_dict = {} for row in rows: logging.info(f'row: "{row}"') - idx = row.index(':') - k, v = row[0: idx], row[idx + 2:] - res_dict[k] = v + row_split = row.split(':', 1) + res_dict[row_split[0]] = row_split[1].strip() logging.info(f'Result dict:\n{res_dict}') return res_dict @@ -229,7 +225,7 @@ def verify_substring(expected_substr, whole_str): f'Expected substring: "{expected_substr}"\n' f'Given (whole) string: "{whole_str}"') - @ staticmethod + @staticmethod def verify_command(cmd_output, should_succeed=True, expected_err=''): """ @summary: @@ -247,7 +243,7 @@ def verify_command(cmd_output, should_succeed=True, expected_err=''): with allure_step(f'Verify that command failed and output contains "{expected_err}"'): ClockUtils.verify_substring(expected_substr=expected_err, whole_str=cmd_output) - @ staticmethod + @staticmethod def verify_timezone_value(duthosts, tz_name, tz_abbreviation): """ @summary: @@ -260,7 +256,6 @@ def verify_timezone_value(duthosts, tz_name, tz_abbreviation): """ with allure_step(f'Verify that given timezone abbreviation "{tz_abbreviation}" matches to ' f'expected timezone "{tz_name}"'): - with allure_step('Get timezone details from timedatectl command'): timedatectl_output = \ ClockUtils.parse_linux_cmd_output(ClockUtils.run_cmd(duthosts, ClockConsts.CMD_TIMEDATECTL)) @@ -279,7 +274,7 @@ def verify_timezone_value(duthosts, tz_name, tz_abbreviation): f'matches the expected timezone "{tz_name}"'): ClockUtils.verify_value(expected=timedatectl_tz_abbreviation, actual=tz_abbreviation) - @ staticmethod + @staticmethod def select_random_date(): """ @summary: @@ -301,7 +296,7 @@ def select_random_date(): logging.info(f'Selected random date: "{rand_date_str}"') return rand_date_str - @ staticmethod + @staticmethod def select_random_time(): """ @summary: @@ -318,7 +313,7 @@ def select_random_time(): logging.info(f'Selected random time: "{rand_time_str}"') return rand_time_str - @ staticmethod + @staticmethod def convert_show_clock_date(show_clock_date): """ @summary: @@ -332,7 +327,7 @@ def convert_show_clock_date(show_clock_date): logging.info(f'Converted date: "{converted_date}"') return converted_date - @ staticmethod + @staticmethod def convert_show_clock_time(show_clock_time): """ @summary: @@ -346,7 +341,7 @@ def convert_show_clock_time(show_clock_time): logging.info(f'Converted time: "{converted_time}"') return converted_time - @ staticmethod + @staticmethod def verify_time(expected, actual, allowed_margin=ClockConsts.TIME_MARGIN): """ @summary: @@ -358,7 +353,6 @@ def verify_time(expected, actual, allowed_margin=ClockConsts.TIME_MARGIN): """ with allure_step(f'Verify that diff between "{expected}" and "{actual}" (in seconds) ' f'is no longer than {allowed_margin}'): - with allure_step(f'Calculate diff between "{expected}" and "{actual}" in seconds'): time_obj1 = datetime.datetime.strptime(expected, "%H:%M:%S") time_obj2 = datetime.datetime.strptime(actual, "%H:%M:%S") @@ -367,3 +361,24 @@ def verify_time(expected, actual, allowed_margin=ClockConsts.TIME_MARGIN): with allure_step(f'Verify that actual diff {diff_seconds} is not larger than {allowed_margin}'): ClockUtils.verify_value(True, diff_seconds <= allowed_margin) + + @staticmethod + def verify_datetime(expected, actual, allowed_margin=ClockConsts.TIME_MARGIN): + """ + @summary: + Asserts a given date-time value is as expected + * expected and actual date-time values are strings in the format "YYYY-MM-DD HH:MM:SS" + @param expected: expected date-time value + @param actual: actual given date-time value + @param allowed_margin: allowed margin between two times (in seconds) + """ + with allure_step(f'Verify that diff between "{expected}" and "{actual}" (in seconds) ' + f'is no longer than {allowed_margin}'): + with allure_step(f'Calculate diff between "{expected}" and "{actual}" in seconds'): + datetime_obj1 = datetime.datetime.strptime(expected, "%Y-%m-%d %H:%M:%S") + datetime_obj2 = datetime.datetime.strptime(actual, "%Y-%m-%d %H:%M:%S") + + diff_seconds = abs((datetime_obj2 - datetime_obj1).total_seconds()) + + with allure_step(f'Verify that actual diff {diff_seconds} is not larger than {allowed_margin}'): + ClockUtils.verify_value(True, diff_seconds <= allowed_margin) diff --git a/tests/clock/test_clock.py b/tests/clock/test_clock.py index ebd651edd3c..3faa83ea62a 100755 --- a/tests/clock/test_clock.py +++ b/tests/clock/test_clock.py @@ -112,13 +112,20 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): show_clock_output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) show_clock_dict = ClockUtils.parse_show_clock_output(show_clock_output) - with allure_step('Verify date'): + with allure_step('Verify date-time'): cur_date = ClockUtils.convert_show_clock_date(show_clock_dict[ClockConsts.DATE]) - ClockUtils.verify_value(expected=new_date, actual=cur_date) - - with allure_step('Verify time'): cur_time = ClockUtils.convert_show_clock_time(show_clock_dict[ClockConsts.TIME]) - ClockUtils.verify_time(expected=new_time, actual=cur_time) + cur_datetime = f'{cur_date} {cur_time}' + + ClockUtils.verify_datetime(expected=new_datetime, actual=cur_datetime) + + # with allure_step('Verify date'): + # cur_date = ClockUtils.convert_show_clock_date(show_clock_dict[ClockConsts.DATE]) + # ClockUtils.verify_value(expected=new_date, actual=cur_date) + # + # with allure_step('Verify time'): + # cur_time = ClockUtils.convert_show_clock_time(show_clock_dict[ClockConsts.TIME]) + # ClockUtils.verify_time(expected=new_time, actual=cur_time) with allure_step('Select random string as invalid input'): rand_str = ''.join(random.choice(string.ascii_lowercase) for i in range(ClockConsts.RANDOM_NUM)) @@ -134,9 +141,8 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): new_date + ' ' + rand_str: ClockConsts.ERR_BAD_TIME.format(rand_str) } - i = 0 for invalid_input, err_msg in errors.items(): - logging.info(f'Invalid input #{i}: "{invalid_input}"\nExpected error:\n{err_msg}') + logging.info(f'Invalid input: "{invalid_input}"\nExpected error:\n{err_msg}') with allure_step('Get show clock output before running the config command'): show_clock_output_before = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) @@ -154,13 +160,22 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): show_clock_dict_before = ClockUtils.parse_show_clock_output(show_clock_output_before) show_clock_dict_after = ClockUtils.parse_show_clock_output(show_clock_output_after) - with allure_step('Verify date'): - ClockUtils.verify_value(expected=show_clock_dict_before[ClockConsts.DATE], - actual=show_clock_dict_after[ClockConsts.DATE]) - - with allure_step('Verify time'): + with allure_step('Verify date-time'): + date_before = ClockUtils.convert_show_clock_date(show_clock_dict_before[ClockConsts.DATE]) time_before = ClockUtils.convert_show_clock_time(show_clock_dict_before[ClockConsts.TIME]) - time_after = ClockUtils.convert_show_clock_time(show_clock_dict_after[ClockConsts.TIME]) - ClockUtils.verify_time(expected=time_before, actual=time_after) + datetime_before = f'{date_before} {time_before}' - i += 1 + date_after = ClockUtils.convert_show_clock_date(show_clock_dict_after[ClockConsts.DATE]) + time_after = ClockUtils.convert_show_clock_time(show_clock_dict_after[ClockConsts.TIME]) + datetime_after = f'{date_after} {time_after}' + + ClockUtils.verify_datetime(expected=datetime_before, actual=datetime_after) + + # with allure_step('Verify date'): + # ClockUtils.verify_value(expected=show_clock_dict_before[ClockConsts.DATE], + # actual=show_clock_dict_after[ClockConsts.DATE]) + # + # with allure_step('Verify time'): + # time_before = ClockUtils.convert_show_clock_time(show_clock_dict_before[ClockConsts.TIME]) + # time_after = ClockUtils.convert_show_clock_time(show_clock_dict_after[ClockConsts.TIME]) + # ClockUtils.verify_time(expected=time_before, actual=time_after) From 4d46f3d3881fc8bc8378a9e86946bae5ebea4e4a Mon Sep 17 00:00:00 2001 From: Alon Navarro Date: Wed, 17 May 2023 19:52:51 +0300 Subject: [PATCH 08/24] pre-commit fixes --- tests/clock/test_clock.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/clock/test_clock.py b/tests/clock/test_clock.py index 3faa83ea62a..fa47df72d06 100755 --- a/tests/clock/test_clock.py +++ b/tests/clock/test_clock.py @@ -2,7 +2,6 @@ import random import string import pytest -import allure from tests.clock.ClockUtils import ClockUtils, allure_step from tests.clock.ClockConsts import ClockConsts @@ -128,17 +127,17 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): # ClockUtils.verify_time(expected=new_time, actual=cur_time) with allure_step('Select random string as invalid input'): - rand_str = ''.join(random.choice(string.ascii_lowercase) for i in range(ClockConsts.RANDOM_NUM)) + rand_str = ''.join(random.choice(string.ascii_lowercase) for _ in range(ClockConsts.RANDOM_NUM)) logging.info(f'Selected random string: "{rand_str}"') with allure_step('Try to set invalid inputs'): errors = { '': ClockConsts.ERR_MISSING_DATE, rand_str: ClockConsts.ERR_MISSING_TIME, - rand_str + ' ' + rand_str: ClockConsts.ERR_BAD_DATE.format(rand_str) + '\n' - + ClockConsts.ERR_BAD_TIME.format(rand_str), - rand_str + ' ' + new_time: ClockConsts.ERR_BAD_DATE.format(rand_str), - new_date + ' ' + rand_str: ClockConsts.ERR_BAD_TIME.format(rand_str) + f'{rand_str} {rand_str}': f'{ClockConsts.ERR_BAD_DATE.format(rand_str)}\n' + f'{ClockConsts.ERR_BAD_TIME.format(rand_str)}', + f'{rand_str} {new_time}': ClockConsts.ERR_BAD_DATE.format(rand_str), + f'{new_date} {rand_str}': ClockConsts.ERR_BAD_TIME.format(rand_str) } for invalid_input, err_msg in errors.items(): From c8c5ac077b05ade63d8de61708579c4914875725 Mon Sep 17 00:00:00 2001 From: Alon Navarro Date: Thu, 18 May 2023 13:16:58 +0300 Subject: [PATCH 09/24] use library for time and date parsing --- tests/clock/ClockUtils.py | 203 ++++++++++---------------------------- tests/clock/test_clock.py | 52 +++------- 2 files changed, 65 insertions(+), 190 deletions(-) diff --git a/tests/clock/ClockUtils.py b/tests/clock/ClockUtils.py index fce3c1c3fa0..136853d586b 100755 --- a/tests/clock/ClockUtils.py +++ b/tests/clock/ClockUtils.py @@ -1,11 +1,11 @@ import logging import random -import datetime -from contextlib import contextmanager - -import allure import time +import datetime as dt +import pytest +import allure +from contextlib import contextmanager from tests.common.helpers.assertions import pytest_assert from tests.clock.ClockConsts import ClockConsts from tests.common.errors import RunAnsibleModuleFail @@ -57,27 +57,35 @@ def run_cmd(duthosts, cmd, param=''): return cmd_output @staticmethod - def parse_show_clock_output(show_clock_output): + def verify_and_parse_show_clock_output(show_clock_output): """ @summary: - Split output of show clock into date, time and timezone strings + Verify, and then split output of show clock into date, time and timezone strings Exapmple: - "Mon 03 Apr 2023 11:29:46 AM UTC" -> {"date": "Mon 03 Apr 2023", "time": "11:29:46 AM", "timezone": "UTC"} + "Mon 03 Apr 2023 11:29:46 PM UTC" -> {"date": "2023-04-03", "time": "23:29:46", "timezone": "+0000"} @param show_clock_output: the given show clock output @return: The splited output as a dict """ - with allure_step('Split output of show clock'): - output_list = show_clock_output.split(' ') - date = ' '.join(output_list[0:4]) - time = ' '.join(output_list[4:6]) - timezone = ' '.join(output_list[6:]) - logging.info(f'Splited output:\ndate: "{date}"\ntime: "{time}"\ntimezone: "{timezone}"') + with allure_step('Verify output of show clock'): + try: + timezone_str = show_clock_output.split()[-1].strip() + logging.info(f'Timezone str: "{timezone_str}"') + date_time_to_parse = show_clock_output.replace(timezone_str, '').strip() + logging.info(f'Time and date to parse: "{date_time_to_parse}"') + + datetime_obj = dt.datetime.strptime(date_time_to_parse, '%a %d %b %Y %I:%M:%S %p') + logging.info(f'Datetime object: "{datetime_obj}"\t|\tType: {type(datetime_obj)}') + except ValueError: + logging.info(f'Show clock output is not valid.\nOutput: "{show_clock_output}"') + pytest.fail(f'Show clock output is not valid.\nOutput: "{show_clock_output}"') + + with allure_step('Split output of show clock'): res = { - ClockConsts.DATE: date, - ClockConsts.TIME: time, - ClockConsts.TIMEZONE: timezone + ClockConsts.DATE: datetime_obj.strftime("%Y-%m-%d"), + ClockConsts.TIME: datetime_obj.strftime("%H:%M:%S"), + ClockConsts.TIMEZONE: timezone_str } logging.info(f'res dict: {res}') @@ -119,36 +127,6 @@ def parse_linux_cmd_output(linux_cmd_output): logging.info(f'Result dict:\n{res_dict}') return res_dict - @staticmethod - def validate_date(date_str): - """ - @summary: - Verify that given string is in a good date format: "Mon 03 Apr 2023" - @param date_str: the given string - """ - with allure_step(f'Validate date for: "{date_str}"'): - try: - datetime.datetime.strptime(date_str, "%a %d %b %Y") - logging.info('Validate date success') - except ValueError: - logging.info('Validate date fail') - pytest_assert(False, f'Given string "{date_str}" is not a valid date') - - @staticmethod - def validate_time(time_str): - """ - @summary: - Verify that given string is in a good time format: "11:29:46 AM" (or PM) - @param time_str: the given string - """ - with allure_step(f'Validate time for: "{time_str}"'): - try: - datetime.datetime.strptime(time_str, "%I:%M:%S %p") - logging.info('Validate time success') - except ValueError: - logging.info('Validate time fail') - pytest_assert(False, f'Given string "{time_str}" is not a valid time') - @staticmethod def get_valid_timezones(duthosts): """ @@ -160,33 +138,6 @@ def get_valid_timezones(duthosts): with allure_step('Get list of valid timezones from show clock timezones command'): return ClockUtils.run_cmd(duthosts=duthosts, cmd=ClockConsts.CMD_SHOW_CLOCK_TIMEZONES).split() - @staticmethod - def validate_timezone(timezone_str, duthosts): - """ - @summary: - Verify that the given string is an abbreviation of a valid timezone - @param timezone_str: the given string - @param duthosts: duthosts - """ - with allure_step(f'Verify that given string "{timezone_str}" is a valid timezone'): - with allure_step('Get timezone from timedatectl linux command'): - timedatectl_output = \ - ClockUtils.parse_linux_cmd_output(ClockUtils.run_cmd(duthosts, ClockConsts.CMD_TIMEDATECTL)) - timedatectl_timezone = timedatectl_output[ClockConsts.TIME_ZONE] - timedatectl_tz_name = timedatectl_timezone.split()[0] - timedatectl_tz_abbreviation = timedatectl_timezone.split(' ')[1].split(',')[0].replace('(', '') - logging.info(f'Timezone in timedatectl: "{timedatectl_timezone}"\nTimezone name: ' - f'"{timedatectl_tz_name}"\nTimezone abbreviation: "{timedatectl_tz_abbreviation}" ') - - with allure_step(f'Verify timezone name "{timedatectl_tz_name}" from timedatectl is in valid timezones'): - valid_timezones = ClockUtils.get_valid_timezones(duthosts) - pytest_assert(timedatectl_tz_name in valid_timezones, - f'Error: string "{timezone_str}" is not in the valid timezones list') - - with allure_step(f'Verify that the given timezone "{timezone_str}" equals to timezone abbreviation in ' - f'timedatectl "{timedatectl_tz_abbreviation}"'): - ClockUtils.verify_value(expected=timedatectl_tz_abbreviation, actual=timezone_str) - @staticmethod def verify_value(expected, actual, should_be_equal=True): """ @@ -244,35 +195,32 @@ def verify_command(cmd_output, should_succeed=True, expected_err=''): ClockUtils.verify_substring(expected_substr=expected_err, whole_str=cmd_output) @staticmethod - def verify_timezone_value(duthosts, tz_name, tz_abbreviation): + def verify_timezone_value(duthosts, expected_tz_name): """ @summary: - Verify that a given timezone abbreviation matches the expected timezone. - * Given timezone abbreviation from show clock command (ETC, IDT, etc.) + Verify that current system timezone is as expected. * Assume that expected timezone should be given as a complete timezone name (ETC/UTC, Asia/Jerusalem, etc.) @param duthosts: duthosts object - @param tz_name: The expected timezone - @param tz_abbreviation: The actual given timezone abbreviation - """ - with allure_step(f'Verify that given timezone abbreviation "{tz_abbreviation}" matches to ' - f'expected timezone "{tz_name}"'): - with allure_step('Get timezone details from timedatectl command'): - timedatectl_output = \ - ClockUtils.parse_linux_cmd_output(ClockUtils.run_cmd(duthosts, ClockConsts.CMD_TIMEDATECTL)) - timedatectl_timezone = timedatectl_output[ClockConsts.TIME_ZONE] - timedatectl_tz_name = timedatectl_timezone.split()[0] - timedatectl_tz_abbreviation = timedatectl_timezone.split(' ')[1].split(',')[0].replace('(', '') - logging.info(f'Timezone in timedatectl: "{timedatectl_timezone}"\n' - f'Timezone name: "{timedatectl_tz_name}"\n' - f'Timezone abbreviation: "{timedatectl_tz_abbreviation}"') - - with allure_step(f'Check that given timezone "{tz_name}" equals to timezone in ' - f'timedatectl "{timedatectl_tz_name}"'): - ClockUtils.verify_value(expected=timedatectl_tz_name, actual=tz_name) - - with allure_step(f'Check that given timezone abbreviation "{tz_abbreviation}" ' - f'matches the expected timezone "{tz_name}"'): - ClockUtils.verify_value(expected=timedatectl_tz_abbreviation, actual=tz_abbreviation) + @param expected_tz_name: The expected timezone name + """ + with allure_step(f'Verify that current system timezone is as expected ({expected_tz_name})'): + with allure_step('Get timezone details from show clock and timedatectl commands'): + show_clock_output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) + show_clock_tz_abbr = ClockUtils.verify_and_parse_show_clock_output( + show_clock_output)[ClockConsts.TIMEZONE] + timedatectl_tz = ClockUtils.parse_linux_cmd_output( + ClockUtils.run_cmd(duthosts, ClockConsts.CMD_TIMEDATECTL))[ClockConsts.TIME_ZONE] + timedatectl_tz_split = timedatectl_tz.split(' ', 1) + timedatectl_tz_name = timedatectl_tz_split[0].strip() + timedatectl_tz_abbr = timedatectl_tz_split[1].split(',', 1)[0].replace('(', '').strip() + + with allure_step(f'Compare timezone abbreviations of show clock ({show_clock_tz_abbr}) ' + f'and timedatectl ({timedatectl_tz_abbr})'): + ClockUtils.verify_value(timedatectl_tz_abbr, show_clock_tz_abbr) + + with allure_step(f'Compare timezone name from timedatectl ({timedatectl_tz_name}) ' + f'to the expected ({expected_tz_name})'): + ClockUtils.verify_value(expected=expected_tz_name, actual=timedatectl_tz_name) @staticmethod def select_random_date(): @@ -282,14 +230,14 @@ def select_random_date(): @return: a random date as string in the format "YYYY-MM-DD" """ with allure_step('Select a random date'): - start_date = datetime.date.fromisoformat(ClockConsts.MIN_SYSTEM_DATE) - end_date = datetime.date.fromisoformat(ClockConsts.MAX_SYSTEM_DATE) + start_date = dt.date.fromisoformat(ClockConsts.MIN_SYSTEM_DATE) + end_date = dt.date.fromisoformat(ClockConsts.MAX_SYSTEM_DATE) diff_days = (end_date - start_date).days rand_num_of_days = random.randint(0, diff_days) - rand_date = start_date + datetime.timedelta(days=rand_num_of_days) + rand_date = start_date + dt.timedelta(days=rand_num_of_days) rand_date_str = rand_date.strftime('%Y-%m-%d') @@ -313,55 +261,6 @@ def select_random_time(): logging.info(f'Selected random time: "{rand_time_str}"') return rand_time_str - @staticmethod - def convert_show_clock_date(show_clock_date): - """ - @summary: - Convert date from show clock to format "YYYY-MM-DD" - e.g. "Wed 12 Apr 2023" --> "2023-04-12" - @param show_clock_date: given date from show clock - @return: converted date - """ - with allure_step(f'Convert date "{show_clock_date}" to format "YYYY-MM-DD"'): - converted_date = datetime.datetime.strptime(show_clock_date, "%a %d %b %Y").strftime("%Y-%m-%d") - logging.info(f'Converted date: "{converted_date}"') - return converted_date - - @staticmethod - def convert_show_clock_time(show_clock_time): - """ - @summary: - Convert time from show clock to format "hh:mm:ss" - e.g. "02:14:28 PM" --> "14:14:28" - @param show_clock_time: given time from show clock - @return: converted me - """ - with allure_step(f'Convert time "{show_clock_time}" to format "hh:mm:ss"'): - converted_time = datetime.datetime.strptime(show_clock_time, "%I:%M:%S %p").strftime("%H:%M:%S") - logging.info(f'Converted time: "{converted_time}"') - return converted_time - - @staticmethod - def verify_time(expected, actual, allowed_margin=ClockConsts.TIME_MARGIN): - """ - @summary: - Asserts a given time value is as expected - * expected and actual time values are strings in the format "HH:MM:SS" - @param expected: expected time value - @param actual: actual given time value - @param allowed_margin: allowed margin between two times (in seconds) - """ - with allure_step(f'Verify that diff between "{expected}" and "{actual}" (in seconds) ' - f'is no longer than {allowed_margin}'): - with allure_step(f'Calculate diff between "{expected}" and "{actual}" in seconds'): - time_obj1 = datetime.datetime.strptime(expected, "%H:%M:%S") - time_obj2 = datetime.datetime.strptime(actual, "%H:%M:%S") - - diff_seconds = abs((time_obj2 - time_obj1).total_seconds()) - - with allure_step(f'Verify that actual diff {diff_seconds} is not larger than {allowed_margin}'): - ClockUtils.verify_value(True, diff_seconds <= allowed_margin) - @staticmethod def verify_datetime(expected, actual, allowed_margin=ClockConsts.TIME_MARGIN): """ @@ -375,8 +274,8 @@ def verify_datetime(expected, actual, allowed_margin=ClockConsts.TIME_MARGIN): with allure_step(f'Verify that diff between "{expected}" and "{actual}" (in seconds) ' f'is no longer than {allowed_margin}'): with allure_step(f'Calculate diff between "{expected}" and "{actual}" in seconds'): - datetime_obj1 = datetime.datetime.strptime(expected, "%Y-%m-%d %H:%M:%S") - datetime_obj2 = datetime.datetime.strptime(actual, "%Y-%m-%d %H:%M:%S") + datetime_obj1 = dt.datetime.strptime(expected, "%Y-%m-%d %H:%M:%S") + datetime_obj2 = dt.datetime.strptime(actual, "%Y-%m-%d %H:%M:%S") diff_seconds = abs((datetime_obj2 - datetime_obj1).total_seconds()) diff --git a/tests/clock/test_clock.py b/tests/clock/test_clock.py index fa47df72d06..252995890d4 100755 --- a/tests/clock/test_clock.py +++ b/tests/clock/test_clock.py @@ -28,10 +28,7 @@ def test_show_clock(duthosts, init_timezone): show_clock_output = ClockUtils.run_cmd(duthosts=duthosts, cmd=ClockConsts.CMD_SHOW_CLOCK) with allure_step('Verify info is valid'): - output_dict = ClockUtils.parse_show_clock_output(show_clock_output) - ClockUtils.validate_date(output_dict[ClockConsts.DATE]) - ClockUtils.validate_time(output_dict[ClockConsts.TIME]) - ClockUtils.validate_timezone(output_dict[ClockConsts.TIMEZONE], duthosts) + ClockUtils.verify_and_parse_show_clock_output(show_clock_output) def test_config_clock_timezone(duthosts, init_timezone): @@ -46,8 +43,8 @@ def test_config_clock_timezone(duthosts, init_timezone): 4. Verify timezone hasn't changed """ valid_timezones = ClockUtils.get_valid_timezones(duthosts) - orig_timezone = ClockUtils \ - .parse_show_clock_output(ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK))[ClockConsts.TIMEZONE] + orig_timezone = ClockUtils.verify_and_parse_show_clock_output( + ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK))[ClockConsts.TIMEZONE] with allure_step('Select a random new valid timezone'): new_timezone = random.choice(valid_timezones) @@ -61,9 +58,7 @@ def test_config_clock_timezone(duthosts, init_timezone): ClockUtils.verify_command(cmd_output=output, should_succeed=True) with allure_step(f'Verify timezone changed to "{new_timezone}"'): - cur_timezone = ClockUtils \ - .parse_show_clock_output(ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK))[ClockConsts.TIMEZONE] - ClockUtils.verify_timezone_value(duthosts, tz_name=new_timezone, tz_abbreviation=cur_timezone) + ClockUtils.verify_timezone_value(duthosts, expected_tz_name=new_timezone) with allure_step('Select a random string as invalid timezone'): invalid_timezone = ''.join(random.choice(string.ascii_lowercase) for _ in range(random.randint(1, 10))) @@ -79,9 +74,7 @@ def test_config_clock_timezone(duthosts, init_timezone): .format(invalid_timezone)) with allure_step('Verify timezone has not changed'): - cur_timezone = ClockUtils \ - .parse_show_clock_output(ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK))[ClockConsts.TIMEZONE] - ClockUtils.verify_timezone_value(duthosts, tz_name=new_timezone, tz_abbreviation=cur_timezone) + ClockUtils.verify_timezone_value(duthosts, expected_tz_name=new_timezone) def test_config_clock_date(duthosts, init_timezone, restore_time): @@ -109,23 +102,15 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): with allure_step(f'Verify date and time changed to "{new_datetime}"'): with allure_step('Get datetime from show clock'): show_clock_output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) - show_clock_dict = ClockUtils.parse_show_clock_output(show_clock_output) + show_clock_dict = ClockUtils.verify_and_parse_show_clock_output(show_clock_output) with allure_step('Verify date-time'): - cur_date = ClockUtils.convert_show_clock_date(show_clock_dict[ClockConsts.DATE]) - cur_time = ClockUtils.convert_show_clock_time(show_clock_dict[ClockConsts.TIME]) + cur_date = show_clock_dict[ClockConsts.DATE] + cur_time = show_clock_dict[ClockConsts.TIME] cur_datetime = f'{cur_date} {cur_time}' ClockUtils.verify_datetime(expected=new_datetime, actual=cur_datetime) - # with allure_step('Verify date'): - # cur_date = ClockUtils.convert_show_clock_date(show_clock_dict[ClockConsts.DATE]) - # ClockUtils.verify_value(expected=new_date, actual=cur_date) - # - # with allure_step('Verify time'): - # cur_time = ClockUtils.convert_show_clock_time(show_clock_dict[ClockConsts.TIME]) - # ClockUtils.verify_time(expected=new_time, actual=cur_time) - with allure_step('Select random string as invalid input'): rand_str = ''.join(random.choice(string.ascii_lowercase) for _ in range(ClockConsts.RANDOM_NUM)) logging.info(f'Selected random string: "{rand_str}"') @@ -156,25 +141,16 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): ClockUtils.verify_command(cmd_output=output, should_succeed=False, expected_err=err_msg) with allure_step(f'Verify date and time have not changed (still "{new_datetime}")'): - show_clock_dict_before = ClockUtils.parse_show_clock_output(show_clock_output_before) - show_clock_dict_after = ClockUtils.parse_show_clock_output(show_clock_output_after) + show_clock_dict_before = ClockUtils.verify_and_parse_show_clock_output(show_clock_output_before) + show_clock_dict_after = ClockUtils.verify_and_parse_show_clock_output(show_clock_output_after) with allure_step('Verify date-time'): - date_before = ClockUtils.convert_show_clock_date(show_clock_dict_before[ClockConsts.DATE]) - time_before = ClockUtils.convert_show_clock_time(show_clock_dict_before[ClockConsts.TIME]) + date_before = show_clock_dict_before[ClockConsts.DATE] + time_before = show_clock_dict_before[ClockConsts.TIME] datetime_before = f'{date_before} {time_before}' - date_after = ClockUtils.convert_show_clock_date(show_clock_dict_after[ClockConsts.DATE]) - time_after = ClockUtils.convert_show_clock_time(show_clock_dict_after[ClockConsts.TIME]) + date_after = show_clock_dict_after[ClockConsts.DATE] + time_after = show_clock_dict_after[ClockConsts.TIME] datetime_after = f'{date_after} {time_after}' ClockUtils.verify_datetime(expected=datetime_before, actual=datetime_after) - - # with allure_step('Verify date'): - # ClockUtils.verify_value(expected=show_clock_dict_before[ClockConsts.DATE], - # actual=show_clock_dict_after[ClockConsts.DATE]) - # - # with allure_step('Verify time'): - # time_before = ClockUtils.convert_show_clock_time(show_clock_dict_before[ClockConsts.TIME]) - # time_after = ClockUtils.convert_show_clock_time(show_clock_dict_after[ClockConsts.TIME]) - # ClockUtils.verify_time(expected=time_before, actual=time_after) From 96b457ebc5b276e95cf7a579aabe6f71cd828e2c Mon Sep 17 00:00:00 2001 From: Alon Navarro Date: Thu, 22 Jun 2023 15:27:56 +0300 Subject: [PATCH 10/24] replace verify methods with straight forward assert --- tests/clock/ClockUtils.py | 66 +++------------------------------------ tests/clock/conftest.py | 15 ++++++--- tests/clock/test_clock.py | 17 ++++++---- 3 files changed, 26 insertions(+), 72 deletions(-) diff --git a/tests/clock/ClockUtils.py b/tests/clock/ClockUtils.py index 136853d586b..374ee1f194e 100755 --- a/tests/clock/ClockUtils.py +++ b/tests/clock/ClockUtils.py @@ -6,7 +6,6 @@ import allure from contextlib import contextmanager -from tests.common.helpers.assertions import pytest_assert from tests.clock.ClockConsts import ClockConsts from tests.common.errors import RunAnsibleModuleFail @@ -121,7 +120,7 @@ def parse_linux_cmd_output(linux_cmd_output): logging.info(f'rows: {rows}') res_dict = {} for row in rows: - logging.info(f'row: "{row}"') + logging.debug(f'row: "{row}"') row_split = row.split(':', 1) res_dict[row_split[0]] = row_split[1].strip() logging.info(f'Result dict:\n{res_dict}') @@ -138,62 +137,6 @@ def get_valid_timezones(duthosts): with allure_step('Get list of valid timezones from show clock timezones command'): return ClockUtils.run_cmd(duthosts=duthosts, cmd=ClockConsts.CMD_SHOW_CLOCK_TIMEZONES).split() - @staticmethod - def verify_value(expected, actual, should_be_equal=True): - """ - @summary: - Asserts a given value is as expected - @param expected: expected value - @param actual: actual given value - @param should_be_equal: whether the values should be equal or not - """ - expected_to_print = "''" if expected == '' else expected - actual_to_print = "''" if actual == '' else actual - - if should_be_equal: - with allure_step(f'Verify that actual value - {expected_to_print} is as expected - {actual_to_print}'): - pytest_assert(actual == expected, f'Error: Values are not equal.\n' - f'Expected: {expected_to_print}\t{type(expected)}\n' - f'Actual: {actual_to_print}\t{type(actual)}') - else: - with allure_step(f'Verify that actual value - {expected_to_print} ' - f'is different than expected - {actual_to_print}'): - pytest_assert(actual != expected, f'Error: Values are equal.\n' - f'Expected: {expected_to_print}\t{type(expected)}\n' - f'Actual: {actual_to_print}\t{type(actual)}') - - @staticmethod - def verify_substring(expected_substr, whole_str): - """ - @summary: - Asserts that a given string contains an expected substring - @param expected_substr: expected substring - @param whole_str: the whole string - """ - with allure_step(f'Verify that string "{whole_str}" contains the substring "{expected_substr}"'): - pytest_assert(expected_substr in whole_str, - f'Error: The given string does not contain the expected substring.\n' - f'Expected substring: "{expected_substr}"\n' - f'Given (whole) string: "{whole_str}"') - - @staticmethod - def verify_command(cmd_output, should_succeed=True, expected_err=''): - """ - @summary: - Verify command success/failure - * doesn't apply on show command - * in case of failure, user can specify an expected error message to be contained in the output - @param cmd_output: the command's output - @param should_succeed: whether the command should succeed or not - @param expected_err: expected error message - """ - if should_succeed: - with allure_step('Verify that command succeeded'): - ClockUtils.verify_value(expected=ClockConsts.OUTPUT_CMD_SUCCESS, actual=cmd_output) - else: - with allure_step(f'Verify that command failed and output contains "{expected_err}"'): - ClockUtils.verify_substring(expected_substr=expected_err, whole_str=cmd_output) - @staticmethod def verify_timezone_value(duthosts, expected_tz_name): """ @@ -216,11 +159,12 @@ def verify_timezone_value(duthosts, expected_tz_name): with allure_step(f'Compare timezone abbreviations of show clock ({show_clock_tz_abbr}) ' f'and timedatectl ({timedatectl_tz_abbr})'): - ClockUtils.verify_value(timedatectl_tz_abbr, show_clock_tz_abbr) + assert timedatectl_tz_abbr == show_clock_tz_abbr, \ + f'Expected: {timedatectl_tz_abbr} == {show_clock_tz_abbr}' with allure_step(f'Compare timezone name from timedatectl ({timedatectl_tz_name}) ' f'to the expected ({expected_tz_name})'): - ClockUtils.verify_value(expected=expected_tz_name, actual=timedatectl_tz_name) + assert timedatectl_tz_name == expected_tz_name, f'Expected: {timedatectl_tz_name} == {expected_tz_name}' @staticmethod def select_random_date(): @@ -280,4 +224,4 @@ def verify_datetime(expected, actual, allowed_margin=ClockConsts.TIME_MARGIN): diff_seconds = abs((datetime_obj2 - datetime_obj1).total_seconds()) with allure_step(f'Verify that actual diff {diff_seconds} is not larger than {allowed_margin}'): - ClockUtils.verify_value(True, diff_seconds <= allowed_margin) + assert diff_seconds <= allowed_margin, f'Expected: {diff_seconds} <= {allowed_margin}' diff --git a/tests/clock/conftest.py b/tests/clock/conftest.py index 10fa094616b..784a29b5e78 100755 --- a/tests/clock/conftest.py +++ b/tests/clock/conftest.py @@ -2,7 +2,6 @@ import time import pytest import logging - from tests.clock.ClockConsts import ClockConsts from tests.clock.ClockUtils import ClockUtils @@ -50,8 +49,11 @@ def restore_time(duthosts, ntp_server): logging.info(f'Reset time after test. Sync with NTP server: {ntp_server}') logging.info(f'Sync with NTP server: {ntp_server}') - ClockUtils.verify_substring(ClockConsts.OUTPUT_CMD_NTP_ADD_SUCCESS.format(ntp_server), - ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_NTP_ADD, ntp_server)) + output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_NTP_ADD, ntp_server) + assert ClockConsts.OUTPUT_CMD_NTP_ADD_SUCCESS.format(ntp_server) in output, \ + f'Error: The given string does not contain the expected substring.\n' \ + f'Expected substring: "{ClockConsts.OUTPUT_CMD_NTP_ADD_SUCCESS.format(ntp_server)}"\n' \ + f'Given (whole) string: "{output}"' logging.info('Check polling time') show_ntp_output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_NTP) @@ -68,5 +70,8 @@ def restore_time(duthosts, ntp_server): time.sleep(polling_time_seconds) logging.info(f'Delete NTP server: {ntp_server}') - ClockUtils.verify_substring(ClockConsts.OUTPUT_CMD_NTP_DEL_SUCCESS.format(ntp_server), - ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_NTP_DEL, ntp_server)) + output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_NTP_DEL, ntp_server) + assert ClockConsts.OUTPUT_CMD_NTP_DEL_SUCCESS.format(ntp_server) in output, \ + f'Error: The given string does not contain the expected substring.\n' \ + f'Expected substring: "{ClockConsts.OUTPUT_CMD_NTP_DEL_SUCCESS.format(ntp_server)}"\n' \ + f'Given (whole) string: "{output}"' diff --git a/tests/clock/test_clock.py b/tests/clock/test_clock.py index 252995890d4..c6eeb7fe0e4 100755 --- a/tests/clock/test_clock.py +++ b/tests/clock/test_clock.py @@ -2,7 +2,6 @@ import random import string import pytest - from tests.clock.ClockUtils import ClockUtils, allure_step from tests.clock.ClockConsts import ClockConsts @@ -55,7 +54,7 @@ def test_config_clock_timezone(duthosts, init_timezone): output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, new_timezone) with allure_step('Verify command success'): - ClockUtils.verify_command(cmd_output=output, should_succeed=True) + assert output == ClockConsts.OUTPUT_CMD_SUCCESS, f'Expected: "{output}" == "{ClockConsts.OUTPUT_CMD_SUCCESS}"' with allure_step(f'Verify timezone changed to "{new_timezone}"'): ClockUtils.verify_timezone_value(duthosts, expected_tz_name=new_timezone) @@ -70,8 +69,11 @@ def test_config_clock_timezone(duthosts, init_timezone): output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, invalid_timezone) with allure_step('Verify command failure'): - ClockUtils.verify_command(cmd_output=output, should_succeed=False, expected_err=ClockConsts.ERR_BAD_TIMEZONE - .format(invalid_timezone)) + expected_err = ClockConsts.ERR_BAD_TIMEZONE.format(invalid_timezone) + assert expected_err in output, \ + f'Error: The given string does not contain the expected substring.\n' \ + f'Expected substring: "{expected_err}"\n' \ + f'Given (whole) string: "{output}"' with allure_step('Verify timezone has not changed'): ClockUtils.verify_timezone_value(duthosts, expected_tz_name=new_timezone) @@ -97,7 +99,7 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_DATE, new_datetime) with allure_step('Verify command success'): - ClockUtils.verify_command(cmd_output=output, should_succeed=True) + assert output == ClockConsts.OUTPUT_CMD_SUCCESS, f'Expected: "{output}" == "{ClockConsts.OUTPUT_CMD_SUCCESS}"' with allure_step(f'Verify date and time changed to "{new_datetime}"'): with allure_step('Get datetime from show clock'): @@ -138,7 +140,10 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): show_clock_output_after = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) with allure_step('Verify command failure'): - ClockUtils.verify_command(cmd_output=output, should_succeed=False, expected_err=err_msg) + assert err_msg in output, \ + f'Error: The given string does not contain the expected substring.\n' \ + f'Expected substring: "{err_msg}"\n' \ + f'Given (whole) string: "{output}"' with allure_step(f'Verify date and time have not changed (still "{new_datetime}")'): show_clock_dict_before = ClockUtils.verify_and_parse_show_clock_output(show_clock_output_before) From ad7f696047fad0dc010e2b7b73d02615e86a7471 Mon Sep 17 00:00:00 2001 From: Alon Navarro Date: Thu, 29 Jun 2023 15:54:51 +0300 Subject: [PATCH 11/24] fix conftest --- tests/clock/conftest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/clock/conftest.py b/tests/clock/conftest.py index 784a29b5e78..592b2d30dac 100755 --- a/tests/clock/conftest.py +++ b/tests/clock/conftest.py @@ -16,10 +16,11 @@ def ntp_server(request): @summary: Return NTP server's ip if given, otherwise skip the test """ ntp_server_ip = request.config.getoption("ntp_server") - logging.info(f'NTP server ip from execution parameter: {ntp_server_ip}') if ntp_server_ip is None: logging.info('IP of NTP server was not given. Skipping the test') pytest.skip("IP of NTP server was not given. Skipping the test") + else: + logging.info(f'NTP server ip from execution parameter: {ntp_server_ip}') return ntp_server_ip From b88eed79f51e64a2d13d3ea792beb36713af5be4 Mon Sep 17 00:00:00 2001 From: Alon Navarro Date: Thu, 29 Jun 2023 16:06:37 +0300 Subject: [PATCH 12/24] log fix in conftest --- tests/clock/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/clock/conftest.py b/tests/clock/conftest.py index 592b2d30dac..a800916fb34 100755 --- a/tests/clock/conftest.py +++ b/tests/clock/conftest.py @@ -20,7 +20,7 @@ def ntp_server(request): logging.info('IP of NTP server was not given. Skipping the test') pytest.skip("IP of NTP server was not given. Skipping the test") else: - logging.info(f'NTP server ip from execution parameter: {ntp_server_ip}') + logging.info(f'NTP server ip from execution parameter: {str(ntp_server_ip)}') return ntp_server_ip From d698c8887aa49d4e285fbb9367bff2aa5d9d2b33 Mon Sep 17 00:00:00 2001 From: Alon Navarro Date: Thu, 29 Jun 2023 16:41:26 +0300 Subject: [PATCH 13/24] fix --- tests/clock/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/clock/conftest.py b/tests/clock/conftest.py index a800916fb34..4f5c6874a36 100755 --- a/tests/clock/conftest.py +++ b/tests/clock/conftest.py @@ -20,7 +20,7 @@ def ntp_server(request): logging.info('IP of NTP server was not given. Skipping the test') pytest.skip("IP of NTP server was not given. Skipping the test") else: - logging.info(f'NTP server ip from execution parameter: {str(ntp_server_ip)}') + logging.info('NTP server ip from execution parameter: {}'.format(ntp_server_ip)) return ntp_server_ip From e09ed3a3717eb923ad6ef34c4be3b0d42b5346fd Mon Sep 17 00:00:00 2001 From: Alon Navarro Date: Tue, 4 Jul 2023 17:03:52 +0300 Subject: [PATCH 14/24] replace strings to the old format --- tests/clock/ClockUtils.py | 57 +++++++++++++++++++-------------------- tests/clock/conftest.py | 32 +++++++++++----------- tests/clock/test_clock.py | 52 ++++++++++++++++++----------------- 3 files changed, 71 insertions(+), 70 deletions(-) diff --git a/tests/clock/ClockUtils.py b/tests/clock/ClockUtils.py index 374ee1f194e..a7bfe194a49 100755 --- a/tests/clock/ClockUtils.py +++ b/tests/clock/ClockUtils.py @@ -18,11 +18,11 @@ def allure_step(step_msg): @param step_msg: The desired step message """ with allure.step(step_msg) as allure_step_context: - logging.info(f'Step start: {step_msg}') + logging.info('Step start: {}'.format(step_msg)) try: yield allure_step_context finally: - logging.info(f'Step end: {step_msg}') + logging.info('Step end: {}'.format(step_msg)) class ClockUtils: @@ -35,11 +35,11 @@ def run_cmd(duthosts, cmd, param=''): while failure returns an error message @return: commands output (str) """ - with allure_step(f'Run command: "{cmd}" with param "{param}"'): + with allure_step('Run command: "{}" with param "{}"'.format(cmd, param)): DUT_HOSTNAME = duthosts[0].hostname cmd_to_run = cmd if param == '' else cmd + ' ' + param - logging.info(f'Actual command to run: "{cmd_to_run}"') + logging.info('Actual command to run: "{}"'.format(cmd_to_run)) try: cmd_output = duthosts.command(cmd_to_run)[DUT_HOSTNAME][ClockConsts.STDOUT] @@ -47,11 +47,11 @@ def run_cmd(duthosts, cmd, param=''): output = cmd_err.results[ClockConsts.STDOUT] err = cmd_err.results[ClockConsts.STDERR] cmd_output = output if output else err - logging.info(f'Command Error!\nError message: "{cmd_output}"') + logging.info('Command Error!\nError message: "{}"'.format(cmd_output)) logging.info('Convert output to string') cmd_output = str(cmd_output) - logging.info(f'Output: {cmd_output}') + logging.info('Output: {}'.format(cmd_output)) return cmd_output @@ -69,16 +69,16 @@ def verify_and_parse_show_clock_output(show_clock_output): with allure_step('Verify output of show clock'): try: timezone_str = show_clock_output.split()[-1].strip() - logging.info(f'Timezone str: "{timezone_str}"') + logging.info('Timezone str: "{}"'.format(timezone_str)) date_time_to_parse = show_clock_output.replace(timezone_str, '').strip() - logging.info(f'Time and date to parse: "{date_time_to_parse}"') + logging.info('Time and date to parse: "{}"'.format(date_time_to_parse)) datetime_obj = dt.datetime.strptime(date_time_to_parse, '%a %d %b %Y %I:%M:%S %p') - logging.info(f'Datetime object: "{datetime_obj}"\t|\tType: {type(datetime_obj)}') + logging.info('Datetime object: "{}"\t|\tType: {}'.format(datetime_obj, type(datetime_obj))) except ValueError: - logging.info(f'Show clock output is not valid.\nOutput: "{show_clock_output}"') - pytest.fail(f'Show clock output is not valid.\nOutput: "{show_clock_output}"') + logging.info('Show clock output is not valid.\nOutput: "{}"'.format(show_clock_output)) + pytest.fail('Show clock output is not valid.\nOutput: "{}"'.format(show_clock_output)) with allure_step('Split output of show clock'): res = { @@ -86,7 +86,7 @@ def verify_and_parse_show_clock_output(show_clock_output): ClockConsts.TIME: datetime_obj.strftime("%H:%M:%S"), ClockConsts.TIMEZONE: timezone_str } - logging.info(f'res dict: {res}') + logging.info('res dict: {}'.format(res)) return res @@ -117,13 +117,13 @@ def parse_linux_cmd_output(linux_cmd_output): """ with allure_step('Parse linux command output into dictionary'): rows = [row.strip() for row in linux_cmd_output.split('\n')] # split by rows - logging.info(f'rows: {rows}') + logging.info('rows: {}'.format(rows)) res_dict = {} for row in rows: - logging.debug(f'row: "{row}"') + logging.debug('row: "{}"'.format(row)) row_split = row.split(':', 1) res_dict[row_split[0]] = row_split[1].strip() - logging.info(f'Result dict:\n{res_dict}') + logging.info('Result dict:\n{}'.format(res_dict)) return res_dict @staticmethod @@ -146,7 +146,7 @@ def verify_timezone_value(duthosts, expected_tz_name): @param duthosts: duthosts object @param expected_tz_name: The expected timezone name """ - with allure_step(f'Verify that current system timezone is as expected ({expected_tz_name})'): + with allure_step('Verify that current system timezone is as expected ({})'.format(expected_tz_name)): with allure_step('Get timezone details from show clock and timedatectl commands'): show_clock_output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) show_clock_tz_abbr = ClockUtils.verify_and_parse_show_clock_output( @@ -157,14 +157,13 @@ def verify_timezone_value(duthosts, expected_tz_name): timedatectl_tz_name = timedatectl_tz_split[0].strip() timedatectl_tz_abbr = timedatectl_tz_split[1].split(',', 1)[0].replace('(', '').strip() - with allure_step(f'Compare timezone abbreviations of show clock ({show_clock_tz_abbr}) ' - f'and timedatectl ({timedatectl_tz_abbr})'): + with allure_step('Compare timezone abbreviations of show clock ({}) and timedatectl ({})' + .format(show_clock_tz_abbr, timedatectl_tz_abbr)): assert timedatectl_tz_abbr == show_clock_tz_abbr, \ - f'Expected: {timedatectl_tz_abbr} == {show_clock_tz_abbr}' + 'Expected: {} == {}'.format(timedatectl_tz_abbr, show_clock_tz_abbr) - with allure_step(f'Compare timezone name from timedatectl ({timedatectl_tz_name}) ' - f'to the expected ({expected_tz_name})'): - assert timedatectl_tz_name == expected_tz_name, f'Expected: {timedatectl_tz_name} == {expected_tz_name}' + with allure_step('Compare timezone name from timedatectl ({}) to the expected ({})'.format(timedatectl_tz_name, expected_tz_name)): + assert timedatectl_tz_name == expected_tz_name, 'Expected: {} == {}'.format(timedatectl_tz_name, expected_tz_name) @staticmethod def select_random_date(): @@ -185,7 +184,7 @@ def select_random_date(): rand_date_str = rand_date.strftime('%Y-%m-%d') - logging.info(f'Selected random date: "{rand_date_str}"') + logging.info('Selected random date: "{}"'.format(rand_date_str)) return rand_date_str @staticmethod @@ -202,7 +201,7 @@ def select_random_time(): rand_time_str = time.strftime("%H:%M:%S", rand_time_obj) - logging.info(f'Selected random time: "{rand_time_str}"') + logging.info('Selected random time: "{}"'.format(rand_time_str)) return rand_time_str @staticmethod @@ -215,13 +214,13 @@ def verify_datetime(expected, actual, allowed_margin=ClockConsts.TIME_MARGIN): @param actual: actual given date-time value @param allowed_margin: allowed margin between two times (in seconds) """ - with allure_step(f'Verify that diff between "{expected}" and "{actual}" (in seconds) ' - f'is no longer than {allowed_margin}'): - with allure_step(f'Calculate diff between "{expected}" and "{actual}" in seconds'): + with allure_step('Verify that diff between "{}" and "{}" (in seconds) is no longer than {}' + .format(expected, actual, allowed_margin)): + with allure_step('Calculate diff between "{}" and "{}" in seconds'.format(expected, actual)): datetime_obj1 = dt.datetime.strptime(expected, "%Y-%m-%d %H:%M:%S") datetime_obj2 = dt.datetime.strptime(actual, "%Y-%m-%d %H:%M:%S") diff_seconds = abs((datetime_obj2 - datetime_obj1).total_seconds()) - with allure_step(f'Verify that actual diff {diff_seconds} is not larger than {allowed_margin}'): - assert diff_seconds <= allowed_margin, f'Expected: {diff_seconds} <= {allowed_margin}' + with allure_step('Verify that actual diff {} is not larger than {}'.format(diff_seconds, allowed_margin)): + assert diff_seconds <= allowed_margin, 'Expected: {} <= {}'.format(diff_seconds, allowed_margin) diff --git a/tests/clock/conftest.py b/tests/clock/conftest.py index 4f5c6874a36..a199184cbf6 100755 --- a/tests/clock/conftest.py +++ b/tests/clock/conftest.py @@ -16,11 +16,10 @@ def ntp_server(request): @summary: Return NTP server's ip if given, otherwise skip the test """ ntp_server_ip = request.config.getoption("ntp_server") + logging.info('NTP server ip from execution parameter: {}'.format(ntp_server_ip)) if ntp_server_ip is None: logging.info('IP of NTP server was not given. Skipping the test') pytest.skip("IP of NTP server was not given. Skipping the test") - else: - logging.info('NTP server ip from execution parameter: {}'.format(ntp_server_ip)) return ntp_server_ip @@ -30,12 +29,12 @@ def init_timezone(duthosts): @summary: fixture to init timezone before and after each test """ - logging.info(f'Set timezone to {ClockConsts.TEST_TIMEZONE} before test') + logging.info('Set timezone to {} before test'.format(ClockConsts.TEST_TIMEZONE)) ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, ClockConsts.TEST_TIMEZONE) yield - logging.info(f'Set timezone to {ClockConsts.TEST_TIMEZONE} after test') + logging.info('Set timezone to {} after test'.format(ClockConsts.TEST_TIMEZONE)) ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, ClockConsts.TEST_TIMEZONE) @@ -47,14 +46,14 @@ def restore_time(duthosts, ntp_server): yield - logging.info(f'Reset time after test. Sync with NTP server: {ntp_server}') + logging.info('Reset time after test. Sync with NTP server: {}'.format(ntp_server)) - logging.info(f'Sync with NTP server: {ntp_server}') + logging.info('Sync with NTP server: {}'.format(ntp_server)) output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_NTP_ADD, ntp_server) assert ClockConsts.OUTPUT_CMD_NTP_ADD_SUCCESS.format(ntp_server) in output, \ - f'Error: The given string does not contain the expected substring.\n' \ - f'Expected substring: "{ClockConsts.OUTPUT_CMD_NTP_ADD_SUCCESS.format(ntp_server)}"\n' \ - f'Given (whole) string: "{output}"' + 'Error: The given string does not contain the expected substring.\n' \ + 'Expected substring: "{}"\n' \ + 'Given (whole) string: "{}"'.format(ClockConsts.OUTPUT_CMD_NTP_ADD_SUCCESS.format(ntp_server), output) logging.info('Check polling time') show_ntp_output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_NTP) @@ -62,17 +61,18 @@ def restore_time(duthosts, ntp_server): if match: polling_time_seconds = int(match.group(1)) else: - logging.info(f'Could not match the regex.\n' - f'Pattern: "{ClockConsts.REGEX_NTP_POLLING_TIME}"\nShow ntp output string: "{show_ntp_output}"') + logging.info('Could not match the regex.\n' + 'Pattern: "{}"\n' + 'Show ntp output string: "{}"'.format(ClockConsts.REGEX_NTP_POLLING_TIME, show_ntp_output)) polling_time_seconds = ClockConsts.RANDOM_NUM - logging.info(f'Polling time (in seconds): {polling_time_seconds + 1}') + logging.info('Polling time (in seconds): {}'.format(polling_time_seconds + 1)) logging.info('Wait for the sync') time.sleep(polling_time_seconds) - logging.info(f'Delete NTP server: {ntp_server}') + logging.info('Delete NTP server: {}'.format(ntp_server)) output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_NTP_DEL, ntp_server) assert ClockConsts.OUTPUT_CMD_NTP_DEL_SUCCESS.format(ntp_server) in output, \ - f'Error: The given string does not contain the expected substring.\n' \ - f'Expected substring: "{ClockConsts.OUTPUT_CMD_NTP_DEL_SUCCESS.format(ntp_server)}"\n' \ - f'Given (whole) string: "{output}"' + 'Error: The given string does not contain the expected substring.\n' \ + 'Expected substring: "{}"\n' \ + 'Given (whole) string: "{}"'.format(ClockConsts.OUTPUT_CMD_NTP_DEL_SUCCESS.format(ntp_server), output) diff --git a/tests/clock/test_clock.py b/tests/clock/test_clock.py index c6eeb7fe0e4..93b057b81ff 100755 --- a/tests/clock/test_clock.py +++ b/tests/clock/test_clock.py @@ -50,30 +50,31 @@ def test_config_clock_timezone(duthosts, init_timezone): while new_timezone == orig_timezone: new_timezone = random.choice(valid_timezones) - with allure_step(f'Set the new timezone "{new_timezone}"'): + with allure_step('Set the new timezone "{}"'.format(new_timezone)): output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, new_timezone) with allure_step('Verify command success'): - assert output == ClockConsts.OUTPUT_CMD_SUCCESS, f'Expected: "{output}" == "{ClockConsts.OUTPUT_CMD_SUCCESS}"' + assert output == ClockConsts.OUTPUT_CMD_SUCCESS, \ + 'Expected: "{}" == "{}"'.format(output, ClockConsts.OUTPUT_CMD_SUCCESS) - with allure_step(f'Verify timezone changed to "{new_timezone}"'): + with allure_step('Verify timezone changed to "{}"'.format(new_timezone)): ClockUtils.verify_timezone_value(duthosts, expected_tz_name=new_timezone) with allure_step('Select a random string as invalid timezone'): invalid_timezone = ''.join(random.choice(string.ascii_lowercase) for _ in range(random.randint(1, 10))) while invalid_timezone in valid_timezones: invalid_timezone = ''.join(random.choice(string.ascii_lowercase) for _ in range(random.randint(1, 10))) - logging.info(f'Selected invalid timezone: "{invalid_timezone}"') + logging.info('Selected invalid timezone: "{}"'.format(invalid_timezone)) - with allure_step(f'Try to set the invalid timezone "{invalid_timezone}"'): + with allure_step('Try to set the invalid timezone "{}"'.format(invalid_timezone)): output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, invalid_timezone) with allure_step('Verify command failure'): expected_err = ClockConsts.ERR_BAD_TIMEZONE.format(invalid_timezone) assert expected_err in output, \ - f'Error: The given string does not contain the expected substring.\n' \ - f'Expected substring: "{expected_err}"\n' \ - f'Given (whole) string: "{output}"' + 'Error: The given string does not contain the expected substring.\n' \ + 'Expected substring: "{}"\n' \ + 'Given (whole) string: "{}"'.format(expected_err, output) with allure_step('Verify timezone has not changed'): ClockUtils.verify_timezone_value(duthosts, expected_tz_name=new_timezone) @@ -95,13 +96,14 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): new_time = ClockUtils.select_random_time() new_datetime = new_date + ' ' + new_time - with allure_step(f'Set new date and time "{new_datetime}"'): + with allure_step('Set new date and time "{}"'.format(new_datetime)): output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_DATE, new_datetime) with allure_step('Verify command success'): - assert output == ClockConsts.OUTPUT_CMD_SUCCESS, f'Expected: "{output}" == "{ClockConsts.OUTPUT_CMD_SUCCESS}"' + assert output == ClockConsts.OUTPUT_CMD_SUCCESS, 'Expected: "{}" == "{}"' \ + .format(output, ClockConsts.OUTPUT_CMD_SUCCESS) - with allure_step(f'Verify date and time changed to "{new_datetime}"'): + with allure_step('Verify date and time changed to "{}"'.format(new_datetime)): with allure_step('Get datetime from show clock'): show_clock_output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) show_clock_dict = ClockUtils.verify_and_parse_show_clock_output(show_clock_output) @@ -109,31 +111,31 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): with allure_step('Verify date-time'): cur_date = show_clock_dict[ClockConsts.DATE] cur_time = show_clock_dict[ClockConsts.TIME] - cur_datetime = f'{cur_date} {cur_time}' + cur_datetime = '{} {}'.format(cur_date, cur_time) ClockUtils.verify_datetime(expected=new_datetime, actual=cur_datetime) with allure_step('Select random string as invalid input'): rand_str = ''.join(random.choice(string.ascii_lowercase) for _ in range(ClockConsts.RANDOM_NUM)) - logging.info(f'Selected random string: "{rand_str}"') + logging.info('Selected random string: "{}"'.format(rand_str)) with allure_step('Try to set invalid inputs'): errors = { '': ClockConsts.ERR_MISSING_DATE, rand_str: ClockConsts.ERR_MISSING_TIME, - f'{rand_str} {rand_str}': f'{ClockConsts.ERR_BAD_DATE.format(rand_str)}\n' - f'{ClockConsts.ERR_BAD_TIME.format(rand_str)}', - f'{rand_str} {new_time}': ClockConsts.ERR_BAD_DATE.format(rand_str), - f'{new_date} {rand_str}': ClockConsts.ERR_BAD_TIME.format(rand_str) + '{} {}'.format(rand_str, rand_str): ClockConsts.ERR_BAD_DATE.format(rand_str) + '\n' + + ClockConsts.ERR_BAD_TIME.format(rand_str), + '{} {}'.format(rand_str, new_time): ClockConsts.ERR_BAD_DATE.format(rand_str), + '{} {}'.format(new_date, rand_str): ClockConsts.ERR_BAD_TIME.format(rand_str) } for invalid_input, err_msg in errors.items(): - logging.info(f'Invalid input: "{invalid_input}"\nExpected error:\n{err_msg}') + logging.info('Invalid input: "{}"\nExpected error:\n{}'.format(invalid_input, err_msg)) with allure_step('Get show clock output before running the config command'): show_clock_output_before = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) - with allure_step(f'Try to set "{invalid_input}"'): + with allure_step('Try to set "{}"'.format(invalid_input)): output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_DATE, invalid_input) with allure_step('Get show clock output after running the config command'): @@ -141,21 +143,21 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): with allure_step('Verify command failure'): assert err_msg in output, \ - f'Error: The given string does not contain the expected substring.\n' \ - f'Expected substring: "{err_msg}"\n' \ - f'Given (whole) string: "{output}"' + 'Error: The given string does not contain the expected substring.\n' \ + 'Expected substring: "{}"\n' \ + 'Given (whole) string: "{}"'.format(err_msg, output) - with allure_step(f'Verify date and time have not changed (still "{new_datetime}")'): + with allure_step('Verify date and time have not changed (still "{}")'.format(new_datetime)): show_clock_dict_before = ClockUtils.verify_and_parse_show_clock_output(show_clock_output_before) show_clock_dict_after = ClockUtils.verify_and_parse_show_clock_output(show_clock_output_after) with allure_step('Verify date-time'): date_before = show_clock_dict_before[ClockConsts.DATE] time_before = show_clock_dict_before[ClockConsts.TIME] - datetime_before = f'{date_before} {time_before}' + datetime_before = '{} {}'.format(date_before, time_before) date_after = show_clock_dict_after[ClockConsts.DATE] time_after = show_clock_dict_after[ClockConsts.TIME] - datetime_after = f'{date_after} {time_after}' + datetime_after = '{} {}'.format(date_after, time_after) ClockUtils.verify_datetime(expected=datetime_before, actual=datetime_after) From 4b7d28629f2394437e27e818620e03aa4398b092 Mon Sep 17 00:00:00 2001 From: Alon Navarro Date: Tue, 4 Jul 2023 17:08:02 +0300 Subject: [PATCH 15/24] pre commit fixes --- tests/clock/ClockUtils.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/clock/ClockUtils.py b/tests/clock/ClockUtils.py index a7bfe194a49..2302b9b69b1 100755 --- a/tests/clock/ClockUtils.py +++ b/tests/clock/ClockUtils.py @@ -162,8 +162,10 @@ def verify_timezone_value(duthosts, expected_tz_name): assert timedatectl_tz_abbr == show_clock_tz_abbr, \ 'Expected: {} == {}'.format(timedatectl_tz_abbr, show_clock_tz_abbr) - with allure_step('Compare timezone name from timedatectl ({}) to the expected ({})'.format(timedatectl_tz_name, expected_tz_name)): - assert timedatectl_tz_name == expected_tz_name, 'Expected: {} == {}'.format(timedatectl_tz_name, expected_tz_name) + with allure_step('Compare timezone name from timedatectl ({}) to the expected ({})' + .format(timedatectl_tz_name, expected_tz_name)): + assert timedatectl_tz_name == expected_tz_name, 'Expected: {} == {}'\ + .format(timedatectl_tz_name, expected_tz_name) @staticmethod def select_random_date(): From 1fac0d7df1f6cd3b88e20e1f98e4fb959dadffb7 Mon Sep 17 00:00:00 2001 From: Alon Navarro Date: Sun, 16 Jul 2023 10:55:52 +0300 Subject: [PATCH 16/24] revert string format changes --- tests/clock/ClockUtils.py | 59 +++++++++++++++++++-------------------- tests/clock/conftest.py | 31 ++++++++++---------- tests/clock/test_clock.py | 52 +++++++++++++++++----------------- 3 files changed, 69 insertions(+), 73 deletions(-) diff --git a/tests/clock/ClockUtils.py b/tests/clock/ClockUtils.py index 2302b9b69b1..374ee1f194e 100755 --- a/tests/clock/ClockUtils.py +++ b/tests/clock/ClockUtils.py @@ -18,11 +18,11 @@ def allure_step(step_msg): @param step_msg: The desired step message """ with allure.step(step_msg) as allure_step_context: - logging.info('Step start: {}'.format(step_msg)) + logging.info(f'Step start: {step_msg}') try: yield allure_step_context finally: - logging.info('Step end: {}'.format(step_msg)) + logging.info(f'Step end: {step_msg}') class ClockUtils: @@ -35,11 +35,11 @@ def run_cmd(duthosts, cmd, param=''): while failure returns an error message @return: commands output (str) """ - with allure_step('Run command: "{}" with param "{}"'.format(cmd, param)): + with allure_step(f'Run command: "{cmd}" with param "{param}"'): DUT_HOSTNAME = duthosts[0].hostname cmd_to_run = cmd if param == '' else cmd + ' ' + param - logging.info('Actual command to run: "{}"'.format(cmd_to_run)) + logging.info(f'Actual command to run: "{cmd_to_run}"') try: cmd_output = duthosts.command(cmd_to_run)[DUT_HOSTNAME][ClockConsts.STDOUT] @@ -47,11 +47,11 @@ def run_cmd(duthosts, cmd, param=''): output = cmd_err.results[ClockConsts.STDOUT] err = cmd_err.results[ClockConsts.STDERR] cmd_output = output if output else err - logging.info('Command Error!\nError message: "{}"'.format(cmd_output)) + logging.info(f'Command Error!\nError message: "{cmd_output}"') logging.info('Convert output to string') cmd_output = str(cmd_output) - logging.info('Output: {}'.format(cmd_output)) + logging.info(f'Output: {cmd_output}') return cmd_output @@ -69,16 +69,16 @@ def verify_and_parse_show_clock_output(show_clock_output): with allure_step('Verify output of show clock'): try: timezone_str = show_clock_output.split()[-1].strip() - logging.info('Timezone str: "{}"'.format(timezone_str)) + logging.info(f'Timezone str: "{timezone_str}"') date_time_to_parse = show_clock_output.replace(timezone_str, '').strip() - logging.info('Time and date to parse: "{}"'.format(date_time_to_parse)) + logging.info(f'Time and date to parse: "{date_time_to_parse}"') datetime_obj = dt.datetime.strptime(date_time_to_parse, '%a %d %b %Y %I:%M:%S %p') - logging.info('Datetime object: "{}"\t|\tType: {}'.format(datetime_obj, type(datetime_obj))) + logging.info(f'Datetime object: "{datetime_obj}"\t|\tType: {type(datetime_obj)}') except ValueError: - logging.info('Show clock output is not valid.\nOutput: "{}"'.format(show_clock_output)) - pytest.fail('Show clock output is not valid.\nOutput: "{}"'.format(show_clock_output)) + logging.info(f'Show clock output is not valid.\nOutput: "{show_clock_output}"') + pytest.fail(f'Show clock output is not valid.\nOutput: "{show_clock_output}"') with allure_step('Split output of show clock'): res = { @@ -86,7 +86,7 @@ def verify_and_parse_show_clock_output(show_clock_output): ClockConsts.TIME: datetime_obj.strftime("%H:%M:%S"), ClockConsts.TIMEZONE: timezone_str } - logging.info('res dict: {}'.format(res)) + logging.info(f'res dict: {res}') return res @@ -117,13 +117,13 @@ def parse_linux_cmd_output(linux_cmd_output): """ with allure_step('Parse linux command output into dictionary'): rows = [row.strip() for row in linux_cmd_output.split('\n')] # split by rows - logging.info('rows: {}'.format(rows)) + logging.info(f'rows: {rows}') res_dict = {} for row in rows: - logging.debug('row: "{}"'.format(row)) + logging.debug(f'row: "{row}"') row_split = row.split(':', 1) res_dict[row_split[0]] = row_split[1].strip() - logging.info('Result dict:\n{}'.format(res_dict)) + logging.info(f'Result dict:\n{res_dict}') return res_dict @staticmethod @@ -146,7 +146,7 @@ def verify_timezone_value(duthosts, expected_tz_name): @param duthosts: duthosts object @param expected_tz_name: The expected timezone name """ - with allure_step('Verify that current system timezone is as expected ({})'.format(expected_tz_name)): + with allure_step(f'Verify that current system timezone is as expected ({expected_tz_name})'): with allure_step('Get timezone details from show clock and timedatectl commands'): show_clock_output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) show_clock_tz_abbr = ClockUtils.verify_and_parse_show_clock_output( @@ -157,15 +157,14 @@ def verify_timezone_value(duthosts, expected_tz_name): timedatectl_tz_name = timedatectl_tz_split[0].strip() timedatectl_tz_abbr = timedatectl_tz_split[1].split(',', 1)[0].replace('(', '').strip() - with allure_step('Compare timezone abbreviations of show clock ({}) and timedatectl ({})' - .format(show_clock_tz_abbr, timedatectl_tz_abbr)): + with allure_step(f'Compare timezone abbreviations of show clock ({show_clock_tz_abbr}) ' + f'and timedatectl ({timedatectl_tz_abbr})'): assert timedatectl_tz_abbr == show_clock_tz_abbr, \ - 'Expected: {} == {}'.format(timedatectl_tz_abbr, show_clock_tz_abbr) + f'Expected: {timedatectl_tz_abbr} == {show_clock_tz_abbr}' - with allure_step('Compare timezone name from timedatectl ({}) to the expected ({})' - .format(timedatectl_tz_name, expected_tz_name)): - assert timedatectl_tz_name == expected_tz_name, 'Expected: {} == {}'\ - .format(timedatectl_tz_name, expected_tz_name) + with allure_step(f'Compare timezone name from timedatectl ({timedatectl_tz_name}) ' + f'to the expected ({expected_tz_name})'): + assert timedatectl_tz_name == expected_tz_name, f'Expected: {timedatectl_tz_name} == {expected_tz_name}' @staticmethod def select_random_date(): @@ -186,7 +185,7 @@ def select_random_date(): rand_date_str = rand_date.strftime('%Y-%m-%d') - logging.info('Selected random date: "{}"'.format(rand_date_str)) + logging.info(f'Selected random date: "{rand_date_str}"') return rand_date_str @staticmethod @@ -203,7 +202,7 @@ def select_random_time(): rand_time_str = time.strftime("%H:%M:%S", rand_time_obj) - logging.info('Selected random time: "{}"'.format(rand_time_str)) + logging.info(f'Selected random time: "{rand_time_str}"') return rand_time_str @staticmethod @@ -216,13 +215,13 @@ def verify_datetime(expected, actual, allowed_margin=ClockConsts.TIME_MARGIN): @param actual: actual given date-time value @param allowed_margin: allowed margin between two times (in seconds) """ - with allure_step('Verify that diff between "{}" and "{}" (in seconds) is no longer than {}' - .format(expected, actual, allowed_margin)): - with allure_step('Calculate diff between "{}" and "{}" in seconds'.format(expected, actual)): + with allure_step(f'Verify that diff between "{expected}" and "{actual}" (in seconds) ' + f'is no longer than {allowed_margin}'): + with allure_step(f'Calculate diff between "{expected}" and "{actual}" in seconds'): datetime_obj1 = dt.datetime.strptime(expected, "%Y-%m-%d %H:%M:%S") datetime_obj2 = dt.datetime.strptime(actual, "%Y-%m-%d %H:%M:%S") diff_seconds = abs((datetime_obj2 - datetime_obj1).total_seconds()) - with allure_step('Verify that actual diff {} is not larger than {}'.format(diff_seconds, allowed_margin)): - assert diff_seconds <= allowed_margin, 'Expected: {} <= {}'.format(diff_seconds, allowed_margin) + with allure_step(f'Verify that actual diff {diff_seconds} is not larger than {allowed_margin}'): + assert diff_seconds <= allowed_margin, f'Expected: {diff_seconds} <= {allowed_margin}' diff --git a/tests/clock/conftest.py b/tests/clock/conftest.py index a199184cbf6..784a29b5e78 100755 --- a/tests/clock/conftest.py +++ b/tests/clock/conftest.py @@ -16,7 +16,7 @@ def ntp_server(request): @summary: Return NTP server's ip if given, otherwise skip the test """ ntp_server_ip = request.config.getoption("ntp_server") - logging.info('NTP server ip from execution parameter: {}'.format(ntp_server_ip)) + logging.info(f'NTP server ip from execution parameter: {ntp_server_ip}') if ntp_server_ip is None: logging.info('IP of NTP server was not given. Skipping the test') pytest.skip("IP of NTP server was not given. Skipping the test") @@ -29,12 +29,12 @@ def init_timezone(duthosts): @summary: fixture to init timezone before and after each test """ - logging.info('Set timezone to {} before test'.format(ClockConsts.TEST_TIMEZONE)) + logging.info(f'Set timezone to {ClockConsts.TEST_TIMEZONE} before test') ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, ClockConsts.TEST_TIMEZONE) yield - logging.info('Set timezone to {} after test'.format(ClockConsts.TEST_TIMEZONE)) + logging.info(f'Set timezone to {ClockConsts.TEST_TIMEZONE} after test') ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, ClockConsts.TEST_TIMEZONE) @@ -46,14 +46,14 @@ def restore_time(duthosts, ntp_server): yield - logging.info('Reset time after test. Sync with NTP server: {}'.format(ntp_server)) + logging.info(f'Reset time after test. Sync with NTP server: {ntp_server}') - logging.info('Sync with NTP server: {}'.format(ntp_server)) + logging.info(f'Sync with NTP server: {ntp_server}') output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_NTP_ADD, ntp_server) assert ClockConsts.OUTPUT_CMD_NTP_ADD_SUCCESS.format(ntp_server) in output, \ - 'Error: The given string does not contain the expected substring.\n' \ - 'Expected substring: "{}"\n' \ - 'Given (whole) string: "{}"'.format(ClockConsts.OUTPUT_CMD_NTP_ADD_SUCCESS.format(ntp_server), output) + f'Error: The given string does not contain the expected substring.\n' \ + f'Expected substring: "{ClockConsts.OUTPUT_CMD_NTP_ADD_SUCCESS.format(ntp_server)}"\n' \ + f'Given (whole) string: "{output}"' logging.info('Check polling time') show_ntp_output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_NTP) @@ -61,18 +61,17 @@ def restore_time(duthosts, ntp_server): if match: polling_time_seconds = int(match.group(1)) else: - logging.info('Could not match the regex.\n' - 'Pattern: "{}"\n' - 'Show ntp output string: "{}"'.format(ClockConsts.REGEX_NTP_POLLING_TIME, show_ntp_output)) + logging.info(f'Could not match the regex.\n' + f'Pattern: "{ClockConsts.REGEX_NTP_POLLING_TIME}"\nShow ntp output string: "{show_ntp_output}"') polling_time_seconds = ClockConsts.RANDOM_NUM - logging.info('Polling time (in seconds): {}'.format(polling_time_seconds + 1)) + logging.info(f'Polling time (in seconds): {polling_time_seconds + 1}') logging.info('Wait for the sync') time.sleep(polling_time_seconds) - logging.info('Delete NTP server: {}'.format(ntp_server)) + logging.info(f'Delete NTP server: {ntp_server}') output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_NTP_DEL, ntp_server) assert ClockConsts.OUTPUT_CMD_NTP_DEL_SUCCESS.format(ntp_server) in output, \ - 'Error: The given string does not contain the expected substring.\n' \ - 'Expected substring: "{}"\n' \ - 'Given (whole) string: "{}"'.format(ClockConsts.OUTPUT_CMD_NTP_DEL_SUCCESS.format(ntp_server), output) + f'Error: The given string does not contain the expected substring.\n' \ + f'Expected substring: "{ClockConsts.OUTPUT_CMD_NTP_DEL_SUCCESS.format(ntp_server)}"\n' \ + f'Given (whole) string: "{output}"' diff --git a/tests/clock/test_clock.py b/tests/clock/test_clock.py index 93b057b81ff..c6eeb7fe0e4 100755 --- a/tests/clock/test_clock.py +++ b/tests/clock/test_clock.py @@ -50,31 +50,30 @@ def test_config_clock_timezone(duthosts, init_timezone): while new_timezone == orig_timezone: new_timezone = random.choice(valid_timezones) - with allure_step('Set the new timezone "{}"'.format(new_timezone)): + with allure_step(f'Set the new timezone "{new_timezone}"'): output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, new_timezone) with allure_step('Verify command success'): - assert output == ClockConsts.OUTPUT_CMD_SUCCESS, \ - 'Expected: "{}" == "{}"'.format(output, ClockConsts.OUTPUT_CMD_SUCCESS) + assert output == ClockConsts.OUTPUT_CMD_SUCCESS, f'Expected: "{output}" == "{ClockConsts.OUTPUT_CMD_SUCCESS}"' - with allure_step('Verify timezone changed to "{}"'.format(new_timezone)): + with allure_step(f'Verify timezone changed to "{new_timezone}"'): ClockUtils.verify_timezone_value(duthosts, expected_tz_name=new_timezone) with allure_step('Select a random string as invalid timezone'): invalid_timezone = ''.join(random.choice(string.ascii_lowercase) for _ in range(random.randint(1, 10))) while invalid_timezone in valid_timezones: invalid_timezone = ''.join(random.choice(string.ascii_lowercase) for _ in range(random.randint(1, 10))) - logging.info('Selected invalid timezone: "{}"'.format(invalid_timezone)) + logging.info(f'Selected invalid timezone: "{invalid_timezone}"') - with allure_step('Try to set the invalid timezone "{}"'.format(invalid_timezone)): + with allure_step(f'Try to set the invalid timezone "{invalid_timezone}"'): output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, invalid_timezone) with allure_step('Verify command failure'): expected_err = ClockConsts.ERR_BAD_TIMEZONE.format(invalid_timezone) assert expected_err in output, \ - 'Error: The given string does not contain the expected substring.\n' \ - 'Expected substring: "{}"\n' \ - 'Given (whole) string: "{}"'.format(expected_err, output) + f'Error: The given string does not contain the expected substring.\n' \ + f'Expected substring: "{expected_err}"\n' \ + f'Given (whole) string: "{output}"' with allure_step('Verify timezone has not changed'): ClockUtils.verify_timezone_value(duthosts, expected_tz_name=new_timezone) @@ -96,14 +95,13 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): new_time = ClockUtils.select_random_time() new_datetime = new_date + ' ' + new_time - with allure_step('Set new date and time "{}"'.format(new_datetime)): + with allure_step(f'Set new date and time "{new_datetime}"'): output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_DATE, new_datetime) with allure_step('Verify command success'): - assert output == ClockConsts.OUTPUT_CMD_SUCCESS, 'Expected: "{}" == "{}"' \ - .format(output, ClockConsts.OUTPUT_CMD_SUCCESS) + assert output == ClockConsts.OUTPUT_CMD_SUCCESS, f'Expected: "{output}" == "{ClockConsts.OUTPUT_CMD_SUCCESS}"' - with allure_step('Verify date and time changed to "{}"'.format(new_datetime)): + with allure_step(f'Verify date and time changed to "{new_datetime}"'): with allure_step('Get datetime from show clock'): show_clock_output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) show_clock_dict = ClockUtils.verify_and_parse_show_clock_output(show_clock_output) @@ -111,31 +109,31 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): with allure_step('Verify date-time'): cur_date = show_clock_dict[ClockConsts.DATE] cur_time = show_clock_dict[ClockConsts.TIME] - cur_datetime = '{} {}'.format(cur_date, cur_time) + cur_datetime = f'{cur_date} {cur_time}' ClockUtils.verify_datetime(expected=new_datetime, actual=cur_datetime) with allure_step('Select random string as invalid input'): rand_str = ''.join(random.choice(string.ascii_lowercase) for _ in range(ClockConsts.RANDOM_NUM)) - logging.info('Selected random string: "{}"'.format(rand_str)) + logging.info(f'Selected random string: "{rand_str}"') with allure_step('Try to set invalid inputs'): errors = { '': ClockConsts.ERR_MISSING_DATE, rand_str: ClockConsts.ERR_MISSING_TIME, - '{} {}'.format(rand_str, rand_str): ClockConsts.ERR_BAD_DATE.format(rand_str) + '\n' + - ClockConsts.ERR_BAD_TIME.format(rand_str), - '{} {}'.format(rand_str, new_time): ClockConsts.ERR_BAD_DATE.format(rand_str), - '{} {}'.format(new_date, rand_str): ClockConsts.ERR_BAD_TIME.format(rand_str) + f'{rand_str} {rand_str}': f'{ClockConsts.ERR_BAD_DATE.format(rand_str)}\n' + f'{ClockConsts.ERR_BAD_TIME.format(rand_str)}', + f'{rand_str} {new_time}': ClockConsts.ERR_BAD_DATE.format(rand_str), + f'{new_date} {rand_str}': ClockConsts.ERR_BAD_TIME.format(rand_str) } for invalid_input, err_msg in errors.items(): - logging.info('Invalid input: "{}"\nExpected error:\n{}'.format(invalid_input, err_msg)) + logging.info(f'Invalid input: "{invalid_input}"\nExpected error:\n{err_msg}') with allure_step('Get show clock output before running the config command'): show_clock_output_before = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) - with allure_step('Try to set "{}"'.format(invalid_input)): + with allure_step(f'Try to set "{invalid_input}"'): output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_DATE, invalid_input) with allure_step('Get show clock output after running the config command'): @@ -143,21 +141,21 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): with allure_step('Verify command failure'): assert err_msg in output, \ - 'Error: The given string does not contain the expected substring.\n' \ - 'Expected substring: "{}"\n' \ - 'Given (whole) string: "{}"'.format(err_msg, output) + f'Error: The given string does not contain the expected substring.\n' \ + f'Expected substring: "{err_msg}"\n' \ + f'Given (whole) string: "{output}"' - with allure_step('Verify date and time have not changed (still "{}")'.format(new_datetime)): + with allure_step(f'Verify date and time have not changed (still "{new_datetime}")'): show_clock_dict_before = ClockUtils.verify_and_parse_show_clock_output(show_clock_output_before) show_clock_dict_after = ClockUtils.verify_and_parse_show_clock_output(show_clock_output_after) with allure_step('Verify date-time'): date_before = show_clock_dict_before[ClockConsts.DATE] time_before = show_clock_dict_before[ClockConsts.TIME] - datetime_before = '{} {}'.format(date_before, time_before) + datetime_before = f'{date_before} {time_before}' date_after = show_clock_dict_after[ClockConsts.DATE] time_after = show_clock_dict_after[ClockConsts.TIME] - datetime_after = '{} {}'.format(date_after, time_after) + datetime_after = f'{date_after} {time_after}' ClockUtils.verify_datetime(expected=datetime_before, actual=datetime_after) From c9382294fae0e008ee059abcafe82811a35a5f22 Mon Sep 17 00:00:00 2001 From: Alon Navarro Date: Sun, 16 Jul 2023 10:59:11 +0300 Subject: [PATCH 17/24] remove log message --- tests/clock/ClockUtils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/clock/ClockUtils.py b/tests/clock/ClockUtils.py index 374ee1f194e..51d22f93f6c 100755 --- a/tests/clock/ClockUtils.py +++ b/tests/clock/ClockUtils.py @@ -49,7 +49,6 @@ def run_cmd(duthosts, cmd, param=''): cmd_output = output if output else err logging.info(f'Command Error!\nError message: "{cmd_output}"') - logging.info('Convert output to string') cmd_output = str(cmd_output) logging.info(f'Output: {cmd_output}') From 93277d8dfb13d152739a8e777db988c3015e381b Mon Sep 17 00:00:00 2001 From: Alon Navarro Date: Tue, 18 Jul 2023 12:00:14 +0300 Subject: [PATCH 18/24] update --- tests/clock/ClockConsts.py | 43 ----- tests/clock/ClockUtils.py | 226 -------------------------- tests/clock/__init__.py | 0 tests/clock/conftest.py | 32 ++-- tests/clock/test_clock.py | 320 +++++++++++++++++++++++++++++++++---- 5 files changed, 308 insertions(+), 313 deletions(-) delete mode 100755 tests/clock/ClockConsts.py delete mode 100755 tests/clock/ClockUtils.py create mode 100755 tests/clock/__init__.py diff --git a/tests/clock/ClockConsts.py b/tests/clock/ClockConsts.py deleted file mode 100755 index 45f705758ca..00000000000 --- a/tests/clock/ClockConsts.py +++ /dev/null @@ -1,43 +0,0 @@ - -class ClockConsts: - STDOUT = "stdout" - STDERR = "stderr" - - DATE = "date" - TIME = "time" - TIMEZONE = "timezone" - - TEST_TIMEZONE = "Asia/Jerusalem" - TIME_MARGIN = 6 - RANDOM_NUM = 6 - - # sonic commands - CMD_SHOW_CLOCK = "show clock" - CMD_SHOW_CLOCK_TIMEZONES = "show clock timezones" - CMD_CONFIG_CLOCK_TIMEZONE = "config clock timezone" - CMD_CONFIG_CLOCK_DATE = "config clock date" - - # expected outputs - OUTPUT_CMD_SUCCESS = '' - - # expected errors - ERR_BAD_TIMEZONE = 'Timezone {} does not conform format' - ERR_MISSING_DATE = 'Error: Missing argument ""' - ERR_MISSING_TIME = 'Error: Missing argument ""' - ERR_BAD_DATE = 'Date {} does not conform format YYYY-MM-DD' - ERR_BAD_TIME = 'Time {} does not conform format HH:MM:SS' - - # timedatectl - CMD_TIMEDATECTL = "timedatectl" - TIME_ZONE = "Time zone" - - MIN_SYSTEM_DATE = "1970-01-01" - MAX_SYSTEM_DATE = "2231-12-31" - - # ntp - CMD_SHOW_NTP = "show ntp" - CMD_CONFIG_NTP_ADD = "config ntp add" - CMD_CONFIG_NTP_DEL = "config ntp del" - OUTPUT_CMD_NTP_ADD_SUCCESS = 'NTP server {} added to configuration\nRestarting ntp-config service...' - OUTPUT_CMD_NTP_DEL_SUCCESS = 'NTP server {} removed from configuration\nRestarting ntp-config service...' - REGEX_NTP_POLLING_TIME = r'polling server every (\d+)' diff --git a/tests/clock/ClockUtils.py b/tests/clock/ClockUtils.py deleted file mode 100755 index 51d22f93f6c..00000000000 --- a/tests/clock/ClockUtils.py +++ /dev/null @@ -1,226 +0,0 @@ -import logging -import random -import time -import datetime as dt -import pytest -import allure - -from contextlib import contextmanager -from tests.clock.ClockConsts import ClockConsts -from tests.common.errors import RunAnsibleModuleFail - - -@contextmanager -def allure_step(step_msg): - """ - @summary: - Context manager that wraps allure step context and a log with the same message - @param step_msg: The desired step message - """ - with allure.step(step_msg) as allure_step_context: - logging.info(f'Step start: {step_msg}') - try: - yield allure_step_context - finally: - logging.info(f'Step end: {step_msg}') - - -class ClockUtils: - @staticmethod - def run_cmd(duthosts, cmd, param=''): - """ - @summary: - Run a given command and return its output. - * A successful command returns an empty output (except for show commands), - while failure returns an error message - @return: commands output (str) - """ - with allure_step(f'Run command: "{cmd}" with param "{param}"'): - DUT_HOSTNAME = duthosts[0].hostname - - cmd_to_run = cmd if param == '' else cmd + ' ' + param - logging.info(f'Actual command to run: "{cmd_to_run}"') - - try: - cmd_output = duthosts.command(cmd_to_run)[DUT_HOSTNAME][ClockConsts.STDOUT] - except RunAnsibleModuleFail as cmd_err: - output = cmd_err.results[ClockConsts.STDOUT] - err = cmd_err.results[ClockConsts.STDERR] - cmd_output = output if output else err - logging.info(f'Command Error!\nError message: "{cmd_output}"') - - cmd_output = str(cmd_output) - logging.info(f'Output: {cmd_output}') - - return cmd_output - - @staticmethod - def verify_and_parse_show_clock_output(show_clock_output): - """ - @summary: - Verify, and then split output of show clock into date, time and timezone strings - - Exapmple: - "Mon 03 Apr 2023 11:29:46 PM UTC" -> {"date": "2023-04-03", "time": "23:29:46", "timezone": "+0000"} - @param show_clock_output: the given show clock output - @return: The splited output as a dict - """ - with allure_step('Verify output of show clock'): - try: - timezone_str = show_clock_output.split()[-1].strip() - logging.info(f'Timezone str: "{timezone_str}"') - - date_time_to_parse = show_clock_output.replace(timezone_str, '').strip() - logging.info(f'Time and date to parse: "{date_time_to_parse}"') - - datetime_obj = dt.datetime.strptime(date_time_to_parse, '%a %d %b %Y %I:%M:%S %p') - logging.info(f'Datetime object: "{datetime_obj}"\t|\tType: {type(datetime_obj)}') - except ValueError: - logging.info(f'Show clock output is not valid.\nOutput: "{show_clock_output}"') - pytest.fail(f'Show clock output is not valid.\nOutput: "{show_clock_output}"') - - with allure_step('Split output of show clock'): - res = { - ClockConsts.DATE: datetime_obj.strftime("%Y-%m-%d"), - ClockConsts.TIME: datetime_obj.strftime("%H:%M:%S"), - ClockConsts.TIMEZONE: timezone_str - } - logging.info(f'res dict: {res}') - - return res - - @staticmethod - def parse_linux_cmd_output(linux_cmd_output): - """ - @summary: - Parse output of a linux command. - - Example: - timedatectl's output: - "Local time: Tue 2023-04-04 08:22:01 MDT - Universal time: Tue 2023-04-04 14:22:01 UTC - RTC time: Tue 2023-04-04 14:22:01 - Time zone: America/Inuvik (MDT, -0600) - System clock synchronized: no - NTP service: n/a - RTC in local TZ: no" - - will become: - { - "Local time": "Tue 2023-04-04 08:22:01 MDT", - "Universal time": "Tue 2023-04-04 14:22:01 UTC", - ... - } - @param linux_cmd_output: given output of a linux command (str) - @return: dictionary as mentioned in the example - """ - with allure_step('Parse linux command output into dictionary'): - rows = [row.strip() for row in linux_cmd_output.split('\n')] # split by rows - logging.info(f'rows: {rows}') - res_dict = {} - for row in rows: - logging.debug(f'row: "{row}"') - row_split = row.split(':', 1) - res_dict[row_split[0]] = row_split[1].strip() - logging.info(f'Result dict:\n{res_dict}') - return res_dict - - @staticmethod - def get_valid_timezones(duthosts): - """ - @summary: - Get the list of valid timezones from 'show clock timezones' command - @param duthosts: duthosts object - @return: list of timezones (strings) - """ - with allure_step('Get list of valid timezones from show clock timezones command'): - return ClockUtils.run_cmd(duthosts=duthosts, cmd=ClockConsts.CMD_SHOW_CLOCK_TIMEZONES).split() - - @staticmethod - def verify_timezone_value(duthosts, expected_tz_name): - """ - @summary: - Verify that current system timezone is as expected. - * Assume that expected timezone should be given as a complete timezone name (ETC/UTC, Asia/Jerusalem, etc.) - @param duthosts: duthosts object - @param expected_tz_name: The expected timezone name - """ - with allure_step(f'Verify that current system timezone is as expected ({expected_tz_name})'): - with allure_step('Get timezone details from show clock and timedatectl commands'): - show_clock_output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) - show_clock_tz_abbr = ClockUtils.verify_and_parse_show_clock_output( - show_clock_output)[ClockConsts.TIMEZONE] - timedatectl_tz = ClockUtils.parse_linux_cmd_output( - ClockUtils.run_cmd(duthosts, ClockConsts.CMD_TIMEDATECTL))[ClockConsts.TIME_ZONE] - timedatectl_tz_split = timedatectl_tz.split(' ', 1) - timedatectl_tz_name = timedatectl_tz_split[0].strip() - timedatectl_tz_abbr = timedatectl_tz_split[1].split(',', 1)[0].replace('(', '').strip() - - with allure_step(f'Compare timezone abbreviations of show clock ({show_clock_tz_abbr}) ' - f'and timedatectl ({timedatectl_tz_abbr})'): - assert timedatectl_tz_abbr == show_clock_tz_abbr, \ - f'Expected: {timedatectl_tz_abbr} == {show_clock_tz_abbr}' - - with allure_step(f'Compare timezone name from timedatectl ({timedatectl_tz_name}) ' - f'to the expected ({expected_tz_name})'): - assert timedatectl_tz_name == expected_tz_name, f'Expected: {timedatectl_tz_name} == {expected_tz_name}' - - @staticmethod - def select_random_date(): - """ - @summary: - Select a random date - @return: a random date as string in the format "YYYY-MM-DD" - """ - with allure_step('Select a random date'): - start_date = dt.date.fromisoformat(ClockConsts.MIN_SYSTEM_DATE) - end_date = dt.date.fromisoformat(ClockConsts.MAX_SYSTEM_DATE) - - diff_days = (end_date - start_date).days - - rand_num_of_days = random.randint(0, diff_days) - - rand_date = start_date + dt.timedelta(days=rand_num_of_days) - - rand_date_str = rand_date.strftime('%Y-%m-%d') - - logging.info(f'Selected random date: "{rand_date_str}"') - return rand_date_str - - @staticmethod - def select_random_time(): - """ - @summary: - Select a random time - @return: a random date as string in the format "hh:mm:ss" - """ - with allure_step('Select a random time in a day'): - rand_num_of_seconds_since_00 = random.randint(0, 24 * 60 * 60 - 1) - - rand_time_obj = time.gmtime(rand_num_of_seconds_since_00) - - rand_time_str = time.strftime("%H:%M:%S", rand_time_obj) - - logging.info(f'Selected random time: "{rand_time_str}"') - return rand_time_str - - @staticmethod - def verify_datetime(expected, actual, allowed_margin=ClockConsts.TIME_MARGIN): - """ - @summary: - Asserts a given date-time value is as expected - * expected and actual date-time values are strings in the format "YYYY-MM-DD HH:MM:SS" - @param expected: expected date-time value - @param actual: actual given date-time value - @param allowed_margin: allowed margin between two times (in seconds) - """ - with allure_step(f'Verify that diff between "{expected}" and "{actual}" (in seconds) ' - f'is no longer than {allowed_margin}'): - with allure_step(f'Calculate diff between "{expected}" and "{actual}" in seconds'): - datetime_obj1 = dt.datetime.strptime(expected, "%Y-%m-%d %H:%M:%S") - datetime_obj2 = dt.datetime.strptime(actual, "%Y-%m-%d %H:%M:%S") - - diff_seconds = abs((datetime_obj2 - datetime_obj1).total_seconds()) - - with allure_step(f'Verify that actual diff {diff_seconds} is not larger than {allowed_margin}'): - assert diff_seconds <= allowed_margin, f'Expected: {diff_seconds} <= {allowed_margin}' diff --git a/tests/clock/__init__.py b/tests/clock/__init__.py new file mode 100755 index 00000000000..e69de29bb2d diff --git a/tests/clock/conftest.py b/tests/clock/conftest.py index 784a29b5e78..e16a6c042ad 100755 --- a/tests/clock/conftest.py +++ b/tests/clock/conftest.py @@ -2,8 +2,8 @@ import time import pytest import logging -from tests.clock.ClockConsts import ClockConsts -from tests.clock.ClockUtils import ClockUtils + +from tests.clock.test_clock import ClockConsts, ClockUtils def pytest_addoption(parser): @@ -16,7 +16,7 @@ def ntp_server(request): @summary: Return NTP server's ip if given, otherwise skip the test """ ntp_server_ip = request.config.getoption("ntp_server") - logging.info(f'NTP server ip from execution parameter: {ntp_server_ip}') + logging.info('NTP server ip from execution parameter: {}'.format(ntp_server_ip)) if ntp_server_ip is None: logging.info('IP of NTP server was not given. Skipping the test') pytest.skip("IP of NTP server was not given. Skipping the test") @@ -29,12 +29,12 @@ def init_timezone(duthosts): @summary: fixture to init timezone before and after each test """ - logging.info(f'Set timezone to {ClockConsts.TEST_TIMEZONE} before test') + logging.info('Set timezone to {} before test'.format(ClockConsts.TEST_TIMEZONE)) ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, ClockConsts.TEST_TIMEZONE) yield - logging.info(f'Set timezone to {ClockConsts.TEST_TIMEZONE} after test') + logging.info('Set timezone to {} after test'.format(ClockConsts.TEST_TIMEZONE)) ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, ClockConsts.TEST_TIMEZONE) @@ -46,14 +46,13 @@ def restore_time(duthosts, ntp_server): yield - logging.info(f'Reset time after test. Sync with NTP server: {ntp_server}') + logging.info('Reset time after test. Sync with NTP server: {}'.format(ntp_server)) - logging.info(f'Sync with NTP server: {ntp_server}') + logging.info('Sync with NTP server: {}'.format(ntp_server)) output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_NTP_ADD, ntp_server) assert ClockConsts.OUTPUT_CMD_NTP_ADD_SUCCESS.format(ntp_server) in output, \ - f'Error: The given string does not contain the expected substring.\n' \ - f'Expected substring: "{ClockConsts.OUTPUT_CMD_NTP_ADD_SUCCESS.format(ntp_server)}"\n' \ - f'Given (whole) string: "{output}"' + 'Error: The given string does not contain the expected substring.\nExpected substring: "{}"\nGiven (whole) ' \ + 'string: "{}"'.format(ClockConsts.OUTPUT_CMD_NTP_ADD_SUCCESS.format(ntp_server), output) logging.info('Check polling time') show_ntp_output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_NTP) @@ -61,17 +60,16 @@ def restore_time(duthosts, ntp_server): if match: polling_time_seconds = int(match.group(1)) else: - logging.info(f'Could not match the regex.\n' - f'Pattern: "{ClockConsts.REGEX_NTP_POLLING_TIME}"\nShow ntp output string: "{show_ntp_output}"') + logging.info('Could not match the regex.\nPattern: "{}"\nShow ntp output string: "{}"' + .format(ClockConsts.REGEX_NTP_POLLING_TIME, show_ntp_output)) polling_time_seconds = ClockConsts.RANDOM_NUM - logging.info(f'Polling time (in seconds): {polling_time_seconds + 1}') + logging.info('Polling time (in seconds): {}'.format(polling_time_seconds + 1)) logging.info('Wait for the sync') time.sleep(polling_time_seconds) - logging.info(f'Delete NTP server: {ntp_server}') + logging.info('Delete NTP server: {}'.format(ntp_server)) output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_NTP_DEL, ntp_server) assert ClockConsts.OUTPUT_CMD_NTP_DEL_SUCCESS.format(ntp_server) in output, \ - f'Error: The given string does not contain the expected substring.\n' \ - f'Expected substring: "{ClockConsts.OUTPUT_CMD_NTP_DEL_SUCCESS.format(ntp_server)}"\n' \ - f'Given (whole) string: "{output}"' + 'Error: The given string does not contain the expected substring.\nExpected substring: "{}"\nGiven (whole) ' \ + 'string: "{}"'.format(ClockConsts.OUTPUT_CMD_NTP_DEL_SUCCESS.format(ntp_server), output) diff --git a/tests/clock/test_clock.py b/tests/clock/test_clock.py index c6eeb7fe0e4..6911059990b 100755 --- a/tests/clock/test_clock.py +++ b/tests/clock/test_clock.py @@ -2,8 +2,12 @@ import random import string import pytest -from tests.clock.ClockUtils import ClockUtils, allure_step -from tests.clock.ClockConsts import ClockConsts +import time +import allure +import datetime as dt + +from contextlib import contextmanager +from tests.common.errors import RunAnsibleModuleFail pytestmark = [ pytest.mark.topology('any'), @@ -14,6 +18,268 @@ ] +@contextmanager +def allure_step(step_msg): + """ + @summary: + Context manager that wraps allure step context and a log with the same message + @param step_msg: The desired step message + """ + with allure.step(step_msg) as allure_step_context: + logging.info('Step start: {}'.format(step_msg)) + try: + yield allure_step_context + finally: + logging.info('Step end: {}'.format(step_msg)) + + +class ClockConsts: + STDOUT = "stdout" + STDERR = "stderr" + + DATE = "date" + TIME = "time" + TIMEZONE = "timezone" + + TEST_TIMEZONE = "Asia/Jerusalem" + TIME_MARGIN = 6 + RANDOM_NUM = 6 + + # sonic commands + CMD_SHOW_CLOCK = "show clock" + CMD_SHOW_CLOCK_TIMEZONES = "show clock timezones" + CMD_CONFIG_CLOCK_TIMEZONE = "config clock timezone" + CMD_CONFIG_CLOCK_DATE = "config clock date" + + # expected outputs + OUTPUT_CMD_SUCCESS = '' + + # expected errors + ERR_BAD_TIMEZONE = 'Timezone {} does not conform format' + ERR_MISSING_DATE = 'Error: Missing argument ""' + ERR_MISSING_TIME = 'Error: Missing argument ""' + ERR_BAD_DATE = 'Date {} does not conform format YYYY-MM-DD' + ERR_BAD_TIME = 'Time {} does not conform format HH:MM:SS' + + # timedatectl + CMD_TIMEDATECTL = "timedatectl" + TIME_ZONE = "Time zone" + + MIN_SYSTEM_DATE = "1970-01-01" + MAX_SYSTEM_DATE = "2231-12-31" + + # ntp + CMD_SHOW_NTP = "show ntp" + CMD_CONFIG_NTP_ADD = "config ntp add" + CMD_CONFIG_NTP_DEL = "config ntp del" + OUTPUT_CMD_NTP_ADD_SUCCESS = 'NTP server {} added to configuration\nRestarting ntp-config service...' + OUTPUT_CMD_NTP_DEL_SUCCESS = 'NTP server {} removed from configuration\nRestarting ntp-config service...' + REGEX_NTP_POLLING_TIME = r'polling server every (\d+)' + + +class ClockUtils: + @staticmethod + def run_cmd(duthosts, cmd, param=''): + """ + @summary: + Run a given command and return its output. + * A successful command returns an empty output (except for show commands), + while failure returns an error message + @return: commands output (str) + """ + with allure_step('Run command: "{}" with param "{}"'.format(cmd, param)): + dut_hostname = duthosts[0].hostname + + cmd_to_run = cmd if param == '' else cmd + ' ' + param + logging.info('Actual command to run: "{}"'.format(cmd_to_run)) + + try: + cmd_output = duthosts.command(cmd_to_run)[dut_hostname][ClockConsts.STDOUT] + except RunAnsibleModuleFail as cmd_err: + output = cmd_err.results[ClockConsts.STDOUT] + err = cmd_err.results[ClockConsts.STDERR] + cmd_output = output if output else err + logging.info('Command Error!\nError message: "{}"'.format(cmd_output)) + + cmd_output = str(cmd_output) + logging.info('Output: {}'.format(cmd_output)) + + return cmd_output + + @staticmethod + def verify_and_parse_show_clock_output(show_clock_output): + """ + @summary: + Verify, and then split output of show clock into date, time and timezone strings + + Exapmple: + "Mon 03 Apr 2023 11:29:46 PM UTC" -> {"date": "2023-04-03", "time": "23:29:46", "timezone": "+0000"} + @param show_clock_output: the given show clock output + @return: The splited output as a dict + """ + with allure_step('Verify output of show clock'): + try: + timezone_str = show_clock_output.split()[-1].strip() + logging.info('Timezone str: "{}"'.format(timezone_str)) + + date_time_to_parse = show_clock_output.replace(timezone_str, '').strip() + logging.info('Time and date to parse: "{}"'.format(date_time_to_parse)) + + datetime_obj = dt.datetime.strptime(date_time_to_parse, '%a %d %b %Y %I:%M:%S %p') + logging.info('Datetime object: "{}"\t|\tType: {}'.format(datetime_obj, type(datetime_obj))) + except ValueError: + logging.info('Show clock output is not valid.\nOutput: "{}"'.format(show_clock_output)) + pytest.fail('Show clock output is not valid.\nOutput: "{}"'.format(show_clock_output)) + + with allure_step('Split output of show clock'): + res = { + ClockConsts.DATE: datetime_obj.strftime("%Y-%m-%d"), + ClockConsts.TIME: datetime_obj.strftime("%H:%M:%S"), + ClockConsts.TIMEZONE: timezone_str + } + logging.info('res dict: {}'.format(res)) + + return res + + @staticmethod + def parse_linux_cmd_output(linux_cmd_output): + """ + @summary: + Parse output of a linux command. + + Example: + timedatectl's output: + "Local time: Tue 2023-04-04 08:22:01 MDT + Universal time: Tue 2023-04-04 14:22:01 UTC + RTC time: Tue 2023-04-04 14:22:01 + Time zone: America/Inuvik (MDT, -0600) + System clock synchronized: no + NTP service: n/a + RTC in local TZ: no" + + will become: + { + "Local time": "Tue 2023-04-04 08:22:01 MDT", + "Universal time": "Tue 2023-04-04 14:22:01 UTC", + ... + } + @param linux_cmd_output: given output of a linux command (str) + @return: dictionary as mentioned in the example + """ + with allure_step('Parse linux command output into dictionary'): + rows = [row.strip() for row in linux_cmd_output.split('\n')] # split by rows + logging.info('rows: {}'.format(rows)) + res_dict = {} + for row in rows: + logging.debug('row: "{}"'.format(row)) + row_split = row.split(':', 1) + res_dict[row_split[0]] = row_split[1].strip() + logging.info('Result dict:\n{}'.format(res_dict)) + return res_dict + + @staticmethod + def get_valid_timezones(duthosts): + """ + @summary: + Get the list of valid timezones from 'show clock timezones' command + @param duthosts: duthosts object + @return: list of timezones (strings) + """ + with allure_step('Get list of valid timezones from show clock timezones command'): + return ClockUtils.run_cmd(duthosts=duthosts, cmd=ClockConsts.CMD_SHOW_CLOCK_TIMEZONES).split() + + @staticmethod + def verify_timezone_value(duthosts, expected_tz_name): + """ + @summary: + Verify that current system timezone is as expected. + * Assume that expected timezone should be given as a complete timezone name (ETC/UTC, Asia/Jerusalem, etc.) + @param duthosts: duthosts object + @param expected_tz_name: The expected timezone name + """ + with allure_step('Verify that current system timezone is as expected ({})'.format(expected_tz_name)): + with allure_step('Get timezone details from show clock and timedatectl commands'): + show_clock_output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) + show_clock_tz_abbr = ClockUtils.verify_and_parse_show_clock_output( + show_clock_output)[ClockConsts.TIMEZONE] + timedatectl_tz = ClockUtils.parse_linux_cmd_output( + ClockUtils.run_cmd(duthosts, ClockConsts.CMD_TIMEDATECTL))[ClockConsts.TIME_ZONE] + timedatectl_tz_split = timedatectl_tz.split(' ', 1) + timedatectl_tz_name = timedatectl_tz_split[0].strip() + timedatectl_tz_abbr = timedatectl_tz_split[1].split(',', 1)[0].replace('(', '').strip() + + with allure_step('Compare timezone abbreviations of show clock ({}) and timedatectl ({})'.format( + show_clock_tz_abbr, timedatectl_tz_abbr)): + assert timedatectl_tz_abbr == show_clock_tz_abbr, 'Expected: {} == {}' \ + .format(timedatectl_tz_abbr, show_clock_tz_abbr) + + with allure_step('Compare timezone name from timedatectl ({}) to the expected ({})'.format( + timedatectl_tz_name, expected_tz_name)): + assert timedatectl_tz_name == expected_tz_name, 'Expected: {} == {}' \ + .format(timedatectl_tz_name, expected_tz_name) + + @staticmethod + def select_random_date(): + """ + @summary: + Select a random date + @return: a random date as string in the format "YYYY-MM-DD" + """ + with allure_step('Select a random date'): + start_date = dt.date.fromisoformat(ClockConsts.MIN_SYSTEM_DATE) + end_date = dt.date.fromisoformat(ClockConsts.MAX_SYSTEM_DATE) + + diff_days = (end_date - start_date).days + + rand_num_of_days = random.randint(0, diff_days) + + rand_date = start_date + dt.timedelta(days=rand_num_of_days) + + rand_date_str = rand_date.strftime('%Y-%m-%d') + + logging.info('Selected random date: "{}"'.format(rand_date_str)) + return rand_date_str + + @staticmethod + def select_random_time(): + """ + @summary: + Select a random time + @return: a random date as string in the format "hh:mm:ss" + """ + with allure_step('Select a random time in a day'): + rand_num_of_seconds_since_00 = random.randint(0, 24 * 60 * 60 - 1) + + rand_time_obj = time.gmtime(rand_num_of_seconds_since_00) + + rand_time_str = time.strftime("%H:%M:%S", rand_time_obj) + + logging.info('Selected random time: "{}"'.format(rand_time_str)) + return rand_time_str + + @staticmethod + def verify_datetime(expected, actual, allowed_margin=ClockConsts.TIME_MARGIN): + """ + @summary: + Asserts a given date-time value is as expected + * expected and actual date-time values are strings in the format "YYYY-MM-DD HH:MM:SS" + @param expected: expected date-time value + @param actual: actual given date-time value + @param allowed_margin: allowed margin between two times (in seconds) + """ + with allure_step( + 'Verify that diff between "{}" and "{}" (in seconds) is no longer than {}'.format(expected, actual, + allowed_margin)): + with allure_step('Calculate diff between "{}" and "{}" in seconds'.format(expected, actual)): + datetime_obj1 = dt.datetime.strptime(expected, "%Y-%m-%d %H:%M:%S") + datetime_obj2 = dt.datetime.strptime(actual, "%Y-%m-%d %H:%M:%S") + + diff_seconds = abs((datetime_obj2 - datetime_obj1).total_seconds()) + + with allure_step('Verify that actual diff {} is not larger than {}'.format(diff_seconds, allowed_margin)): + assert diff_seconds <= allowed_margin, 'Expected: {} <= {}'.format(diff_seconds, allowed_margin) + + def test_show_clock(duthosts, init_timezone): """ @summary: @@ -50,30 +316,30 @@ def test_config_clock_timezone(duthosts, init_timezone): while new_timezone == orig_timezone: new_timezone = random.choice(valid_timezones) - with allure_step(f'Set the new timezone "{new_timezone}"'): + with allure_step('Set the new timezone "{}"'.format(new_timezone)): output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, new_timezone) with allure_step('Verify command success'): - assert output == ClockConsts.OUTPUT_CMD_SUCCESS, f'Expected: "{output}" == "{ClockConsts.OUTPUT_CMD_SUCCESS}"' + assert output == ClockConsts.OUTPUT_CMD_SUCCESS, 'Expected: "{}" == "{}"'.format(output, + ClockConsts.OUTPUT_CMD_SUCCESS) - with allure_step(f'Verify timezone changed to "{new_timezone}"'): + with allure_step('Verify timezone changed to "{}"'.format(new_timezone)): ClockUtils.verify_timezone_value(duthosts, expected_tz_name=new_timezone) with allure_step('Select a random string as invalid timezone'): invalid_timezone = ''.join(random.choice(string.ascii_lowercase) for _ in range(random.randint(1, 10))) while invalid_timezone in valid_timezones: invalid_timezone = ''.join(random.choice(string.ascii_lowercase) for _ in range(random.randint(1, 10))) - logging.info(f'Selected invalid timezone: "{invalid_timezone}"') + logging.info('Selected invalid timezone: "{}"'.format(invalid_timezone)) - with allure_step(f'Try to set the invalid timezone "{invalid_timezone}"'): + with allure_step('Try to set the invalid timezone "{}"'.format(invalid_timezone)): output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, invalid_timezone) with allure_step('Verify command failure'): expected_err = ClockConsts.ERR_BAD_TIMEZONE.format(invalid_timezone) assert expected_err in output, \ - f'Error: The given string does not contain the expected substring.\n' \ - f'Expected substring: "{expected_err}"\n' \ - f'Given (whole) string: "{output}"' + 'Error: The given string does not contain the expected substring.\nExpected substring: "{}"\n' \ + 'Given (whole) string: "{}"'.format(expected_err, output) with allure_step('Verify timezone has not changed'): ClockUtils.verify_timezone_value(duthosts, expected_tz_name=new_timezone) @@ -95,13 +361,14 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): new_time = ClockUtils.select_random_time() new_datetime = new_date + ' ' + new_time - with allure_step(f'Set new date and time "{new_datetime}"'): + with allure_step('Set new date and time "{}"'.format(new_datetime)): output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_DATE, new_datetime) with allure_step('Verify command success'): - assert output == ClockConsts.OUTPUT_CMD_SUCCESS, f'Expected: "{output}" == "{ClockConsts.OUTPUT_CMD_SUCCESS}"' + assert output == ClockConsts.OUTPUT_CMD_SUCCESS, 'Expected: "{}" == "{}"'.format(output, + ClockConsts.OUTPUT_CMD_SUCCESS) - with allure_step(f'Verify date and time changed to "{new_datetime}"'): + with allure_step('Verify date and time changed to "{}"'.format(new_datetime)): with allure_step('Get datetime from show clock'): show_clock_output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) show_clock_dict = ClockUtils.verify_and_parse_show_clock_output(show_clock_output) @@ -109,31 +376,31 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): with allure_step('Verify date-time'): cur_date = show_clock_dict[ClockConsts.DATE] cur_time = show_clock_dict[ClockConsts.TIME] - cur_datetime = f'{cur_date} {cur_time}' + cur_datetime = '{} {}'.format(cur_date, cur_time) ClockUtils.verify_datetime(expected=new_datetime, actual=cur_datetime) with allure_step('Select random string as invalid input'): rand_str = ''.join(random.choice(string.ascii_lowercase) for _ in range(ClockConsts.RANDOM_NUM)) - logging.info(f'Selected random string: "{rand_str}"') + logging.info('Selected random string: "{}"'.format(rand_str)) with allure_step('Try to set invalid inputs'): errors = { '': ClockConsts.ERR_MISSING_DATE, rand_str: ClockConsts.ERR_MISSING_TIME, - f'{rand_str} {rand_str}': f'{ClockConsts.ERR_BAD_DATE.format(rand_str)}\n' - f'{ClockConsts.ERR_BAD_TIME.format(rand_str)}', - f'{rand_str} {new_time}': ClockConsts.ERR_BAD_DATE.format(rand_str), - f'{new_date} {rand_str}': ClockConsts.ERR_BAD_TIME.format(rand_str) + '{} {}'.format(rand_str, rand_str): '{}\n{}'.format(ClockConsts.ERR_BAD_DATE.format(rand_str), + ClockConsts.ERR_BAD_TIME.format(rand_str)), + '{} {}'.format(rand_str, new_time): ClockConsts.ERR_BAD_DATE.format(rand_str), + '{} {}'.format(new_date, rand_str): ClockConsts.ERR_BAD_TIME.format(rand_str) } for invalid_input, err_msg in errors.items(): - logging.info(f'Invalid input: "{invalid_input}"\nExpected error:\n{err_msg}') + logging.info('Invalid input: "{}"\nExpected error:\n{}'.format(invalid_input, err_msg)) with allure_step('Get show clock output before running the config command'): show_clock_output_before = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) - with allure_step(f'Try to set "{invalid_input}"'): + with allure_step('Try to set "{}"'.format(invalid_input)): output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_DATE, invalid_input) with allure_step('Get show clock output after running the config command'): @@ -141,21 +408,20 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): with allure_step('Verify command failure'): assert err_msg in output, \ - f'Error: The given string does not contain the expected substring.\n' \ - f'Expected substring: "{err_msg}"\n' \ - f'Given (whole) string: "{output}"' + 'Error: The given string does not contain the expected substring.\nExpected substring: "{}"\n' \ + 'Given (whole) string: "{}"'.format(err_msg, output) - with allure_step(f'Verify date and time have not changed (still "{new_datetime}")'): + with allure_step('Verify date and time have not changed (still "{}")'.format(new_datetime)): show_clock_dict_before = ClockUtils.verify_and_parse_show_clock_output(show_clock_output_before) show_clock_dict_after = ClockUtils.verify_and_parse_show_clock_output(show_clock_output_after) with allure_step('Verify date-time'): date_before = show_clock_dict_before[ClockConsts.DATE] time_before = show_clock_dict_before[ClockConsts.TIME] - datetime_before = f'{date_before} {time_before}' + datetime_before = '{} {}'.format(date_before, time_before) date_after = show_clock_dict_after[ClockConsts.DATE] time_after = show_clock_dict_after[ClockConsts.TIME] - datetime_after = f'{date_after} {time_after}' + datetime_after = '{} {}'.format(date_after, time_after) ClockUtils.verify_datetime(expected=datetime_before, actual=datetime_after) From 1263499091832fe306f6a14202ba20460740b468 Mon Sep 17 00:00:00 2001 From: Alon Navarro Date: Mon, 7 Aug 2023 10:43:46 +0300 Subject: [PATCH 19/24] replace strings format --- tests/clock/conftest.py | 24 +++++---- tests/clock/test_clock.py | 111 +++++++++++++++++++------------------- 2 files changed, 68 insertions(+), 67 deletions(-) diff --git a/tests/clock/conftest.py b/tests/clock/conftest.py index e16a6c042ad..a05597de4b4 100755 --- a/tests/clock/conftest.py +++ b/tests/clock/conftest.py @@ -16,7 +16,7 @@ def ntp_server(request): @summary: Return NTP server's ip if given, otherwise skip the test """ ntp_server_ip = request.config.getoption("ntp_server") - logging.info('NTP server ip from execution parameter: {}'.format(ntp_server_ip)) + logging.info(f'NTP server ip from execution parameter: {ntp_server_ip}') if ntp_server_ip is None: logging.info('IP of NTP server was not given. Skipping the test') pytest.skip("IP of NTP server was not given. Skipping the test") @@ -29,12 +29,12 @@ def init_timezone(duthosts): @summary: fixture to init timezone before and after each test """ - logging.info('Set timezone to {} before test'.format(ClockConsts.TEST_TIMEZONE)) + logging.info(f'Set timezone to {ClockConsts.TEST_TIMEZONE} before test') ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, ClockConsts.TEST_TIMEZONE) yield - logging.info('Set timezone to {} after test'.format(ClockConsts.TEST_TIMEZONE)) + logging.info(f'Set timezone to {ClockConsts.TEST_TIMEZONE} after test') ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, ClockConsts.TEST_TIMEZONE) @@ -46,13 +46,14 @@ def restore_time(duthosts, ntp_server): yield - logging.info('Reset time after test. Sync with NTP server: {}'.format(ntp_server)) + logging.info(f'Reset time after test. Sync with NTP server: {ntp_server}') - logging.info('Sync with NTP server: {}'.format(ntp_server)) + logging.info(f'Sync with NTP server: {ntp_server}') output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_NTP_ADD, ntp_server) assert ClockConsts.OUTPUT_CMD_NTP_ADD_SUCCESS.format(ntp_server) in output, \ - 'Error: The given string does not contain the expected substring.\nExpected substring: "{}"\nGiven (whole) ' \ - 'string: "{}"'.format(ClockConsts.OUTPUT_CMD_NTP_ADD_SUCCESS.format(ntp_server), output) + f'Error: The given string does not contain the expected substring.\n' \ + f'Expected substring: "{ClockConsts.OUTPUT_CMD_NTP_ADD_SUCCESS.format(ntp_server)}"\n' \ + f'Given (whole) string: "{output}"' logging.info('Check polling time') show_ntp_output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_NTP) @@ -63,13 +64,14 @@ def restore_time(duthosts, ntp_server): logging.info('Could not match the regex.\nPattern: "{}"\nShow ntp output string: "{}"' .format(ClockConsts.REGEX_NTP_POLLING_TIME, show_ntp_output)) polling_time_seconds = ClockConsts.RANDOM_NUM - logging.info('Polling time (in seconds): {}'.format(polling_time_seconds + 1)) + logging.info(f'Polling time (in seconds): {polling_time_seconds + 1}') logging.info('Wait for the sync') time.sleep(polling_time_seconds) - logging.info('Delete NTP server: {}'.format(ntp_server)) + logging.info(f'Delete NTP server: {ntp_server}') output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_NTP_DEL, ntp_server) assert ClockConsts.OUTPUT_CMD_NTP_DEL_SUCCESS.format(ntp_server) in output, \ - 'Error: The given string does not contain the expected substring.\nExpected substring: "{}"\nGiven (whole) ' \ - 'string: "{}"'.format(ClockConsts.OUTPUT_CMD_NTP_DEL_SUCCESS.format(ntp_server), output) + f'Error: The given string does not contain the expected substring.\n' \ + f'Expected substring: "{ClockConsts.OUTPUT_CMD_NTP_DEL_SUCCESS.format(ntp_server)}"\n' \ + f'Given (whole) string: "{output}"' diff --git a/tests/clock/test_clock.py b/tests/clock/test_clock.py index 6911059990b..84d8423b28b 100755 --- a/tests/clock/test_clock.py +++ b/tests/clock/test_clock.py @@ -26,11 +26,11 @@ def allure_step(step_msg): @param step_msg: The desired step message """ with allure.step(step_msg) as allure_step_context: - logging.info('Step start: {}'.format(step_msg)) + logging.info(f'Step start: {step_msg}') try: yield allure_step_context finally: - logging.info('Step end: {}'.format(step_msg)) + logging.info(f'Step end: {step_msg}') class ClockConsts: @@ -87,11 +87,11 @@ def run_cmd(duthosts, cmd, param=''): while failure returns an error message @return: commands output (str) """ - with allure_step('Run command: "{}" with param "{}"'.format(cmd, param)): + with allure_step(f'Run command: "{cmd}" with param "{param}"'): dut_hostname = duthosts[0].hostname cmd_to_run = cmd if param == '' else cmd + ' ' + param - logging.info('Actual command to run: "{}"'.format(cmd_to_run)) + logging.info(f'Actual command to run: "{cmd_to_run}"') try: cmd_output = duthosts.command(cmd_to_run)[dut_hostname][ClockConsts.STDOUT] @@ -99,10 +99,10 @@ def run_cmd(duthosts, cmd, param=''): output = cmd_err.results[ClockConsts.STDOUT] err = cmd_err.results[ClockConsts.STDERR] cmd_output = output if output else err - logging.info('Command Error!\nError message: "{}"'.format(cmd_output)) + logging.info(f'Command Error!\nError message: "{cmd_output}"') cmd_output = str(cmd_output) - logging.info('Output: {}'.format(cmd_output)) + logging.info(f'Output: {cmd_output}') return cmd_output @@ -120,16 +120,16 @@ def verify_and_parse_show_clock_output(show_clock_output): with allure_step('Verify output of show clock'): try: timezone_str = show_clock_output.split()[-1].strip() - logging.info('Timezone str: "{}"'.format(timezone_str)) + logging.info(f'Timezone str: "{timezone_str}"') date_time_to_parse = show_clock_output.replace(timezone_str, '').strip() - logging.info('Time and date to parse: "{}"'.format(date_time_to_parse)) + logging.info(f'Time and date to parse: "{date_time_to_parse}"') datetime_obj = dt.datetime.strptime(date_time_to_parse, '%a %d %b %Y %I:%M:%S %p') - logging.info('Datetime object: "{}"\t|\tType: {}'.format(datetime_obj, type(datetime_obj))) + logging.info(f'Datetime object: "{datetime_obj}"\t|\tType: {type(datetime_obj)}') except ValueError: - logging.info('Show clock output is not valid.\nOutput: "{}"'.format(show_clock_output)) - pytest.fail('Show clock output is not valid.\nOutput: "{}"'.format(show_clock_output)) + logging.info(f'Show clock output is not valid.\nOutput: "{show_clock_output}"') + pytest.fail(f'Show clock output is not valid.\nOutput: "{show_clock_output}"') with allure_step('Split output of show clock'): res = { @@ -137,7 +137,7 @@ def verify_and_parse_show_clock_output(show_clock_output): ClockConsts.TIME: datetime_obj.strftime("%H:%M:%S"), ClockConsts.TIMEZONE: timezone_str } - logging.info('res dict: {}'.format(res)) + logging.info(f'res dict: {res}') return res @@ -168,13 +168,13 @@ def parse_linux_cmd_output(linux_cmd_output): """ with allure_step('Parse linux command output into dictionary'): rows = [row.strip() for row in linux_cmd_output.split('\n')] # split by rows - logging.info('rows: {}'.format(rows)) + logging.info(f'rows: {rows}') res_dict = {} for row in rows: - logging.debug('row: "{}"'.format(row)) + logging.debug(f'row: "{row}"') row_split = row.split(':', 1) res_dict[row_split[0]] = row_split[1].strip() - logging.info('Result dict:\n{}'.format(res_dict)) + logging.info(f'Result dict:\n{res_dict}') return res_dict @staticmethod @@ -197,7 +197,7 @@ def verify_timezone_value(duthosts, expected_tz_name): @param duthosts: duthosts object @param expected_tz_name: The expected timezone name """ - with allure_step('Verify that current system timezone is as expected ({})'.format(expected_tz_name)): + with allure_step(f'Verify that current system timezone is as expected ({expected_tz_name})'): with allure_step('Get timezone details from show clock and timedatectl commands'): show_clock_output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) show_clock_tz_abbr = ClockUtils.verify_and_parse_show_clock_output( @@ -208,15 +208,14 @@ def verify_timezone_value(duthosts, expected_tz_name): timedatectl_tz_name = timedatectl_tz_split[0].strip() timedatectl_tz_abbr = timedatectl_tz_split[1].split(',', 1)[0].replace('(', '').strip() - with allure_step('Compare timezone abbreviations of show clock ({}) and timedatectl ({})'.format( - show_clock_tz_abbr, timedatectl_tz_abbr)): - assert timedatectl_tz_abbr == show_clock_tz_abbr, 'Expected: {} == {}' \ - .format(timedatectl_tz_abbr, show_clock_tz_abbr) + with allure_step(f'Compare timezone abbreviations of show clock ({show_clock_tz_abbr}) ' + f'and timedatectl ({timedatectl_tz_abbr})'): + assert timedatectl_tz_abbr == show_clock_tz_abbr, \ + 'Expected: {timedatectl_tz_abbr} == {show_clock_tz_abbr}' - with allure_step('Compare timezone name from timedatectl ({}) to the expected ({})'.format( - timedatectl_tz_name, expected_tz_name)): - assert timedatectl_tz_name == expected_tz_name, 'Expected: {} == {}' \ - .format(timedatectl_tz_name, expected_tz_name) + with allure_step(f'Compare timezone name from timedatectl ({timedatectl_tz_name}) ' + f'to the expected ({expected_tz_name})'): + assert timedatectl_tz_name == expected_tz_name, f'Expected: {timedatectl_tz_name} == {expected_tz_name}' @staticmethod def select_random_date(): @@ -237,7 +236,7 @@ def select_random_date(): rand_date_str = rand_date.strftime('%Y-%m-%d') - logging.info('Selected random date: "{}"'.format(rand_date_str)) + logging.info(f'Selected random date: "{rand_date_str}"') return rand_date_str @staticmethod @@ -254,7 +253,7 @@ def select_random_time(): rand_time_str = time.strftime("%H:%M:%S", rand_time_obj) - logging.info('Selected random time: "{}"'.format(rand_time_str)) + logging.info(f'Selected random time: "{rand_time_str}"') return rand_time_str @staticmethod @@ -268,16 +267,16 @@ def verify_datetime(expected, actual, allowed_margin=ClockConsts.TIME_MARGIN): @param allowed_margin: allowed margin between two times (in seconds) """ with allure_step( - 'Verify that diff between "{}" and "{}" (in seconds) is no longer than {}'.format(expected, actual, - allowed_margin)): - with allure_step('Calculate diff between "{}" and "{}" in seconds'.format(expected, actual)): + f'Verify that diff between "{expected}" and "{actual}" (in seconds) is ' + f'no longer than {allowed_margin}'): + with allure_step(f'Calculate diff between "{expected}" and "{actual}" in seconds'): datetime_obj1 = dt.datetime.strptime(expected, "%Y-%m-%d %H:%M:%S") datetime_obj2 = dt.datetime.strptime(actual, "%Y-%m-%d %H:%M:%S") diff_seconds = abs((datetime_obj2 - datetime_obj1).total_seconds()) - with allure_step('Verify that actual diff {} is not larger than {}'.format(diff_seconds, allowed_margin)): - assert diff_seconds <= allowed_margin, 'Expected: {} <= {}'.format(diff_seconds, allowed_margin) + with allure_step(f'Verify that actual diff {diff_seconds} is not larger than {allowed_margin}'): + assert diff_seconds <= allowed_margin, f'Expected: {diff_seconds} <= {allowed_margin}' def test_show_clock(duthosts, init_timezone): @@ -316,30 +315,30 @@ def test_config_clock_timezone(duthosts, init_timezone): while new_timezone == orig_timezone: new_timezone = random.choice(valid_timezones) - with allure_step('Set the new timezone "{}"'.format(new_timezone)): + with allure_step(f'Set the new timezone "{new_timezone}"'): output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, new_timezone) with allure_step('Verify command success'): - assert output == ClockConsts.OUTPUT_CMD_SUCCESS, 'Expected: "{}" == "{}"'.format(output, - ClockConsts.OUTPUT_CMD_SUCCESS) + assert output == ClockConsts.OUTPUT_CMD_SUCCESS, f'Expected: "{output}" == "{ClockConsts.OUTPUT_CMD_SUCCESS}"' - with allure_step('Verify timezone changed to "{}"'.format(new_timezone)): + with allure_step(f'Verify timezone changed to "{new_timezone}"'): ClockUtils.verify_timezone_value(duthosts, expected_tz_name=new_timezone) with allure_step('Select a random string as invalid timezone'): invalid_timezone = ''.join(random.choice(string.ascii_lowercase) for _ in range(random.randint(1, 10))) while invalid_timezone in valid_timezones: invalid_timezone = ''.join(random.choice(string.ascii_lowercase) for _ in range(random.randint(1, 10))) - logging.info('Selected invalid timezone: "{}"'.format(invalid_timezone)) + logging.info(f'Selected invalid timezone: "{invalid_timezone}"') - with allure_step('Try to set the invalid timezone "{}"'.format(invalid_timezone)): + with allure_step(f'Try to set the invalid timezone "{invalid_timezone}"'): output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, invalid_timezone) with allure_step('Verify command failure'): expected_err = ClockConsts.ERR_BAD_TIMEZONE.format(invalid_timezone) assert expected_err in output, \ - 'Error: The given string does not contain the expected substring.\nExpected substring: "{}"\n' \ - 'Given (whole) string: "{}"'.format(expected_err, output) + f'Error: The given string does not contain the expected substring.\n' \ + f'Expected substring: "{expected_err}"\n' \ + f'Given (whole) string: "{output}"' with allure_step('Verify timezone has not changed'): ClockUtils.verify_timezone_value(duthosts, expected_tz_name=new_timezone) @@ -361,14 +360,13 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): new_time = ClockUtils.select_random_time() new_datetime = new_date + ' ' + new_time - with allure_step('Set new date and time "{}"'.format(new_datetime)): + with allure_step(f'Set new date and time "{new_datetime}"'): output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_DATE, new_datetime) with allure_step('Verify command success'): - assert output == ClockConsts.OUTPUT_CMD_SUCCESS, 'Expected: "{}" == "{}"'.format(output, - ClockConsts.OUTPUT_CMD_SUCCESS) + assert output == ClockConsts.OUTPUT_CMD_SUCCESS, f'Expected: "{output}" == "{ClockConsts.OUTPUT_CMD_SUCCESS}"' - with allure_step('Verify date and time changed to "{}"'.format(new_datetime)): + with allure_step(f'Verify date and time changed to "{new_datetime}"'): with allure_step('Get datetime from show clock'): show_clock_output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) show_clock_dict = ClockUtils.verify_and_parse_show_clock_output(show_clock_output) @@ -376,31 +374,31 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): with allure_step('Verify date-time'): cur_date = show_clock_dict[ClockConsts.DATE] cur_time = show_clock_dict[ClockConsts.TIME] - cur_datetime = '{} {}'.format(cur_date, cur_time) + cur_datetime = f'{cur_date} {cur_time}' ClockUtils.verify_datetime(expected=new_datetime, actual=cur_datetime) with allure_step('Select random string as invalid input'): rand_str = ''.join(random.choice(string.ascii_lowercase) for _ in range(ClockConsts.RANDOM_NUM)) - logging.info('Selected random string: "{}"'.format(rand_str)) + logging.info(f'Selected random string: "{rand_str}"') with allure_step('Try to set invalid inputs'): errors = { '': ClockConsts.ERR_MISSING_DATE, rand_str: ClockConsts.ERR_MISSING_TIME, - '{} {}'.format(rand_str, rand_str): '{}\n{}'.format(ClockConsts.ERR_BAD_DATE.format(rand_str), - ClockConsts.ERR_BAD_TIME.format(rand_str)), - '{} {}'.format(rand_str, new_time): ClockConsts.ERR_BAD_DATE.format(rand_str), - '{} {}'.format(new_date, rand_str): ClockConsts.ERR_BAD_TIME.format(rand_str) + f'{rand_str} {rand_str}': f'{ClockConsts.ERR_BAD_DATE.format(rand_str)}\n' + f'{ClockConsts.ERR_BAD_TIME.format(rand_str)}', + f'{rand_str} {new_time}': ClockConsts.ERR_BAD_DATE.format(rand_str), + f'{new_date} {rand_str}': ClockConsts.ERR_BAD_TIME.format(rand_str) } for invalid_input, err_msg in errors.items(): - logging.info('Invalid input: "{}"\nExpected error:\n{}'.format(invalid_input, err_msg)) + logging.info(f'Invalid input: "{invalid_input}"\nExpected error:\n{err_msg}') with allure_step('Get show clock output before running the config command'): show_clock_output_before = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) - with allure_step('Try to set "{}"'.format(invalid_input)): + with allure_step(f'Try to set "{invalid_input}"'): output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_DATE, invalid_input) with allure_step('Get show clock output after running the config command'): @@ -408,20 +406,21 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): with allure_step('Verify command failure'): assert err_msg in output, \ - 'Error: The given string does not contain the expected substring.\nExpected substring: "{}"\n' \ - 'Given (whole) string: "{}"'.format(err_msg, output) + f'Error: The given string does not contain the expected substring.\n' \ + f'Expected substring: "{err_msg}"\n' \ + f'Given (whole) string: "{output}"' - with allure_step('Verify date and time have not changed (still "{}")'.format(new_datetime)): + with allure_step(f'Verify date and time have not changed (still "{new_datetime}")'): show_clock_dict_before = ClockUtils.verify_and_parse_show_clock_output(show_clock_output_before) show_clock_dict_after = ClockUtils.verify_and_parse_show_clock_output(show_clock_output_after) with allure_step('Verify date-time'): date_before = show_clock_dict_before[ClockConsts.DATE] time_before = show_clock_dict_before[ClockConsts.TIME] - datetime_before = '{} {}'.format(date_before, time_before) + datetime_before = f'{date_before} {time_before}' date_after = show_clock_dict_after[ClockConsts.DATE] time_after = show_clock_dict_after[ClockConsts.TIME] - datetime_after = '{} {}'.format(date_after, time_after) + datetime_after = f'{date_after} {time_after}' ClockUtils.verify_datetime(expected=datetime_before, actual=datetime_after) From e039ae8ac42f0ef8ff384460154d01cc44657b90 Mon Sep 17 00:00:00 2001 From: Alon Navarro Date: Mon, 7 Aug 2023 11:05:46 +0300 Subject: [PATCH 20/24] use existing allure step util --- tests/clock/conftest.py | 3 +- tests/clock/test_clock.py | 94 +++++++++++++++++---------------------- 2 files changed, 41 insertions(+), 56 deletions(-) diff --git a/tests/clock/conftest.py b/tests/clock/conftest.py index a05597de4b4..3fb71be0c6c 100755 --- a/tests/clock/conftest.py +++ b/tests/clock/conftest.py @@ -18,8 +18,7 @@ def ntp_server(request): ntp_server_ip = request.config.getoption("ntp_server") logging.info(f'NTP server ip from execution parameter: {ntp_server_ip}') if ntp_server_ip is None: - logging.info('IP of NTP server was not given. Skipping the test') - pytest.skip("IP of NTP server was not given. Skipping the test") + pytest.fail("IP of NTP server was not given") return ntp_server_ip diff --git a/tests/clock/test_clock.py b/tests/clock/test_clock.py index 84d8423b28b..5fa0d57b1ba 100755 --- a/tests/clock/test_clock.py +++ b/tests/clock/test_clock.py @@ -3,11 +3,12 @@ import string import pytest import time -import allure +# import allure import datetime as dt from contextlib import contextmanager from tests.common.errors import RunAnsibleModuleFail +from tests.common.plugins.allure_wrapper import allure_step_wrapper as allure pytestmark = [ pytest.mark.topology('any'), @@ -18,21 +19,6 @@ ] -@contextmanager -def allure_step(step_msg): - """ - @summary: - Context manager that wraps allure step context and a log with the same message - @param step_msg: The desired step message - """ - with allure.step(step_msg) as allure_step_context: - logging.info(f'Step start: {step_msg}') - try: - yield allure_step_context - finally: - logging.info(f'Step end: {step_msg}') - - class ClockConsts: STDOUT = "stdout" STDERR = "stderr" @@ -87,7 +73,7 @@ def run_cmd(duthosts, cmd, param=''): while failure returns an error message @return: commands output (str) """ - with allure_step(f'Run command: "{cmd}" with param "{param}"'): + with allure.step(f'Run command: "{cmd}" with param "{param}"'): dut_hostname = duthosts[0].hostname cmd_to_run = cmd if param == '' else cmd + ' ' + param @@ -117,7 +103,7 @@ def verify_and_parse_show_clock_output(show_clock_output): @param show_clock_output: the given show clock output @return: The splited output as a dict """ - with allure_step('Verify output of show clock'): + with allure.step('Verify output of show clock'): try: timezone_str = show_clock_output.split()[-1].strip() logging.info(f'Timezone str: "{timezone_str}"') @@ -131,7 +117,7 @@ def verify_and_parse_show_clock_output(show_clock_output): logging.info(f'Show clock output is not valid.\nOutput: "{show_clock_output}"') pytest.fail(f'Show clock output is not valid.\nOutput: "{show_clock_output}"') - with allure_step('Split output of show clock'): + with allure.step('Split output of show clock'): res = { ClockConsts.DATE: datetime_obj.strftime("%Y-%m-%d"), ClockConsts.TIME: datetime_obj.strftime("%H:%M:%S"), @@ -166,7 +152,7 @@ def parse_linux_cmd_output(linux_cmd_output): @param linux_cmd_output: given output of a linux command (str) @return: dictionary as mentioned in the example """ - with allure_step('Parse linux command output into dictionary'): + with allure.step('Parse linux command output into dictionary'): rows = [row.strip() for row in linux_cmd_output.split('\n')] # split by rows logging.info(f'rows: {rows}') res_dict = {} @@ -185,7 +171,7 @@ def get_valid_timezones(duthosts): @param duthosts: duthosts object @return: list of timezones (strings) """ - with allure_step('Get list of valid timezones from show clock timezones command'): + with allure.step('Get list of valid timezones from show clock timezones command'): return ClockUtils.run_cmd(duthosts=duthosts, cmd=ClockConsts.CMD_SHOW_CLOCK_TIMEZONES).split() @staticmethod @@ -197,8 +183,8 @@ def verify_timezone_value(duthosts, expected_tz_name): @param duthosts: duthosts object @param expected_tz_name: The expected timezone name """ - with allure_step(f'Verify that current system timezone is as expected ({expected_tz_name})'): - with allure_step('Get timezone details from show clock and timedatectl commands'): + with allure.step(f'Verify that current system timezone is as expected ({expected_tz_name})'): + with allure.step('Get timezone details from show clock and timedatectl commands'): show_clock_output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) show_clock_tz_abbr = ClockUtils.verify_and_parse_show_clock_output( show_clock_output)[ClockConsts.TIMEZONE] @@ -208,12 +194,12 @@ def verify_timezone_value(duthosts, expected_tz_name): timedatectl_tz_name = timedatectl_tz_split[0].strip() timedatectl_tz_abbr = timedatectl_tz_split[1].split(',', 1)[0].replace('(', '').strip() - with allure_step(f'Compare timezone abbreviations of show clock ({show_clock_tz_abbr}) ' + with allure.step(f'Compare timezone abbreviations of show clock ({show_clock_tz_abbr}) ' f'and timedatectl ({timedatectl_tz_abbr})'): assert timedatectl_tz_abbr == show_clock_tz_abbr, \ 'Expected: {timedatectl_tz_abbr} == {show_clock_tz_abbr}' - with allure_step(f'Compare timezone name from timedatectl ({timedatectl_tz_name}) ' + with allure.step(f'Compare timezone name from timedatectl ({timedatectl_tz_name}) ' f'to the expected ({expected_tz_name})'): assert timedatectl_tz_name == expected_tz_name, f'Expected: {timedatectl_tz_name} == {expected_tz_name}' @@ -224,7 +210,7 @@ def select_random_date(): Select a random date @return: a random date as string in the format "YYYY-MM-DD" """ - with allure_step('Select a random date'): + with allure.step('Select a random date'): start_date = dt.date.fromisoformat(ClockConsts.MIN_SYSTEM_DATE) end_date = dt.date.fromisoformat(ClockConsts.MAX_SYSTEM_DATE) @@ -246,7 +232,7 @@ def select_random_time(): Select a random time @return: a random date as string in the format "hh:mm:ss" """ - with allure_step('Select a random time in a day'): + with allure.step('Select a random time in a day'): rand_num_of_seconds_since_00 = random.randint(0, 24 * 60 * 60 - 1) rand_time_obj = time.gmtime(rand_num_of_seconds_since_00) @@ -266,16 +252,16 @@ def verify_datetime(expected, actual, allowed_margin=ClockConsts.TIME_MARGIN): @param actual: actual given date-time value @param allowed_margin: allowed margin between two times (in seconds) """ - with allure_step( + with allure.step( f'Verify that diff between "{expected}" and "{actual}" (in seconds) is ' f'no longer than {allowed_margin}'): - with allure_step(f'Calculate diff between "{expected}" and "{actual}" in seconds'): + with allure.step(f'Calculate diff between "{expected}" and "{actual}" in seconds'): datetime_obj1 = dt.datetime.strptime(expected, "%Y-%m-%d %H:%M:%S") datetime_obj2 = dt.datetime.strptime(actual, "%Y-%m-%d %H:%M:%S") diff_seconds = abs((datetime_obj2 - datetime_obj1).total_seconds()) - with allure_step(f'Verify that actual diff {diff_seconds} is not larger than {allowed_margin}'): + with allure.step(f'Verify that actual diff {diff_seconds} is not larger than {allowed_margin}'): assert diff_seconds <= allowed_margin, f'Expected: {diff_seconds} <= {allowed_margin}' @@ -288,10 +274,10 @@ def test_show_clock(duthosts, init_timezone): 1. Run show clock 2. Validate info """ - with allure_step('Run show clock command'): + with allure.step('Run show clock command'): show_clock_output = ClockUtils.run_cmd(duthosts=duthosts, cmd=ClockConsts.CMD_SHOW_CLOCK) - with allure_step('Verify info is valid'): + with allure.step('Verify info is valid'): ClockUtils.verify_and_parse_show_clock_output(show_clock_output) @@ -310,37 +296,37 @@ def test_config_clock_timezone(duthosts, init_timezone): orig_timezone = ClockUtils.verify_and_parse_show_clock_output( ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK))[ClockConsts.TIMEZONE] - with allure_step('Select a random new valid timezone'): + with allure.step('Select a random new valid timezone'): new_timezone = random.choice(valid_timezones) while new_timezone == orig_timezone: new_timezone = random.choice(valid_timezones) - with allure_step(f'Set the new timezone "{new_timezone}"'): + with allure.step(f'Set the new timezone "{new_timezone}"'): output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, new_timezone) - with allure_step('Verify command success'): + with allure.step('Verify command success'): assert output == ClockConsts.OUTPUT_CMD_SUCCESS, f'Expected: "{output}" == "{ClockConsts.OUTPUT_CMD_SUCCESS}"' - with allure_step(f'Verify timezone changed to "{new_timezone}"'): + with allure.step(f'Verify timezone changed to "{new_timezone}"'): ClockUtils.verify_timezone_value(duthosts, expected_tz_name=new_timezone) - with allure_step('Select a random string as invalid timezone'): + with allure.step('Select a random string as invalid timezone'): invalid_timezone = ''.join(random.choice(string.ascii_lowercase) for _ in range(random.randint(1, 10))) while invalid_timezone in valid_timezones: invalid_timezone = ''.join(random.choice(string.ascii_lowercase) for _ in range(random.randint(1, 10))) logging.info(f'Selected invalid timezone: "{invalid_timezone}"') - with allure_step(f'Try to set the invalid timezone "{invalid_timezone}"'): + with allure.step(f'Try to set the invalid timezone "{invalid_timezone}"'): output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, invalid_timezone) - with allure_step('Verify command failure'): + with allure.step('Verify command failure'): expected_err = ClockConsts.ERR_BAD_TIMEZONE.format(invalid_timezone) assert expected_err in output, \ f'Error: The given string does not contain the expected substring.\n' \ f'Expected substring: "{expected_err}"\n' \ f'Given (whole) string: "{output}"' - with allure_step('Verify timezone has not changed'): + with allure.step('Verify timezone has not changed'): ClockUtils.verify_timezone_value(duthosts, expected_tz_name=new_timezone) @@ -355,34 +341,34 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): 3. Try to set invalid date and time 4. Verify error and that time hasn't changed """ - with allure_step('Select valid date and time to set'): + with allure.step('Select valid date and time to set'): new_date = ClockUtils.select_random_date() new_time = ClockUtils.select_random_time() new_datetime = new_date + ' ' + new_time - with allure_step(f'Set new date and time "{new_datetime}"'): + with allure.step(f'Set new date and time "{new_datetime}"'): output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_DATE, new_datetime) - with allure_step('Verify command success'): + with allure.step('Verify command success'): assert output == ClockConsts.OUTPUT_CMD_SUCCESS, f'Expected: "{output}" == "{ClockConsts.OUTPUT_CMD_SUCCESS}"' - with allure_step(f'Verify date and time changed to "{new_datetime}"'): - with allure_step('Get datetime from show clock'): + with allure.step(f'Verify date and time changed to "{new_datetime}"'): + with allure.step('Get datetime from show clock'): show_clock_output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) show_clock_dict = ClockUtils.verify_and_parse_show_clock_output(show_clock_output) - with allure_step('Verify date-time'): + with allure.step('Verify date-time'): cur_date = show_clock_dict[ClockConsts.DATE] cur_time = show_clock_dict[ClockConsts.TIME] cur_datetime = f'{cur_date} {cur_time}' ClockUtils.verify_datetime(expected=new_datetime, actual=cur_datetime) - with allure_step('Select random string as invalid input'): + with allure.step('Select random string as invalid input'): rand_str = ''.join(random.choice(string.ascii_lowercase) for _ in range(ClockConsts.RANDOM_NUM)) logging.info(f'Selected random string: "{rand_str}"') - with allure_step('Try to set invalid inputs'): + with allure.step('Try to set invalid inputs'): errors = { '': ClockConsts.ERR_MISSING_DATE, rand_str: ClockConsts.ERR_MISSING_TIME, @@ -395,26 +381,26 @@ def test_config_clock_date(duthosts, init_timezone, restore_time): for invalid_input, err_msg in errors.items(): logging.info(f'Invalid input: "{invalid_input}"\nExpected error:\n{err_msg}') - with allure_step('Get show clock output before running the config command'): + with allure.step('Get show clock output before running the config command'): show_clock_output_before = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) - with allure_step(f'Try to set "{invalid_input}"'): + with allure.step(f'Try to set "{invalid_input}"'): output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_DATE, invalid_input) - with allure_step('Get show clock output after running the config command'): + with allure.step('Get show clock output after running the config command'): show_clock_output_after = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_CLOCK) - with allure_step('Verify command failure'): + with allure.step('Verify command failure'): assert err_msg in output, \ f'Error: The given string does not contain the expected substring.\n' \ f'Expected substring: "{err_msg}"\n' \ f'Given (whole) string: "{output}"' - with allure_step(f'Verify date and time have not changed (still "{new_datetime}")'): + with allure.step(f'Verify date and time have not changed (still "{new_datetime}")'): show_clock_dict_before = ClockUtils.verify_and_parse_show_clock_output(show_clock_output_before) show_clock_dict_after = ClockUtils.verify_and_parse_show_clock_output(show_clock_output_after) - with allure_step('Verify date-time'): + with allure.step('Verify date-time'): date_before = show_clock_dict_before[ClockConsts.DATE] time_before = show_clock_dict_before[ClockConsts.TIME] datetime_before = f'{date_before} {time_before}' From f1d13ee0977acc2a20563f727266e5fe94cdb653 Mon Sep 17 00:00:00 2001 From: Alon Navarro Date: Mon, 7 Aug 2023 11:11:51 +0300 Subject: [PATCH 21/24] remove unused import --- tests/clock/test_clock.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/clock/test_clock.py b/tests/clock/test_clock.py index 5fa0d57b1ba..0606b2cdc07 100755 --- a/tests/clock/test_clock.py +++ b/tests/clock/test_clock.py @@ -3,10 +3,8 @@ import string import pytest import time -# import allure import datetime as dt -from contextlib import contextmanager from tests.common.errors import RunAnsibleModuleFail from tests.common.plugins.allure_wrapper import allure_step_wrapper as allure From a4ceb37756c96dc5d92efda85c81d6de82c2649b Mon Sep 17 00:00:00 2001 From: Alon Navarro Date: Mon, 7 Aug 2023 14:57:05 +0300 Subject: [PATCH 22/24] remove and restore ntp that configured before test --- tests/clock/conftest.py | 47 +++++++++++++++++++++++++++++++++++++++ tests/clock/test_clock.py | 12 +++------- 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/tests/clock/conftest.py b/tests/clock/conftest.py index 3fb71be0c6c..78a2916d9cb 100755 --- a/tests/clock/conftest.py +++ b/tests/clock/conftest.py @@ -42,6 +42,28 @@ def restore_time(duthosts, ntp_server): """ @summary: fixture to restore time after test (using ntp) """ + logging.info('Check if there is ntp configured before test') + show_ntp_output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_NTP) + if 'unsynchronised' in show_ntp_output: + logging.info('There is no NTP server configured before test') + orig_ntp_server = None + else: + synchronized_str = 'synchronised to NTP server' + logging.info('There is NTP server configured before test') + assert synchronized_str in show_ntp_output, f'There is NTP configured but output do not contain ' \ + f'"{synchronized_str}"' + orig_ntp_server = re.findall(r'\d+.\d+.\d+.\d+', + re.findall(r'synchronised to NTP server \(\d+.\d+.\d+.\d+\)', + show_ntp_output)[0])[0] + logging.info(f'Original NTP: {orig_ntp_server}') + + if orig_ntp_server: + logging.info('Disable original NTP before test') + output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_NTP_DEL, orig_ntp_server) + assert ClockConsts.OUTPUT_CMD_NTP_DEL_SUCCESS.format(orig_ntp_server) in output, \ + f'Error: The given string does not contain the expected substring.\n' \ + f'Expected substring: "{ClockConsts.OUTPUT_CMD_NTP_DEL_SUCCESS.format(orig_ntp_server)}"\n' \ + f'Given (whole) string: "{output}"' yield @@ -74,3 +96,28 @@ def restore_time(duthosts, ntp_server): f'Error: The given string does not contain the expected substring.\n' \ f'Expected substring: "{ClockConsts.OUTPUT_CMD_NTP_DEL_SUCCESS.format(ntp_server)}"\n' \ f'Given (whole) string: "{output}"' + + logging.info('Wait for the sync') + time.sleep(polling_time_seconds) + + if orig_ntp_server: + logging.info('Restore original NTP server after test') + output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_NTP_ADD, orig_ntp_server) + assert ClockConsts.OUTPUT_CMD_NTP_ADD_SUCCESS.format(orig_ntp_server) in output, \ + f'Error: The given string does not contain the expected substring.\n' \ + f'Expected substring: "{ClockConsts.OUTPUT_CMD_NTP_ADD_SUCCESS.format(orig_ntp_server)}"\n' \ + f'Given (whole) string: "{output}"' + + logging.info('Check polling time') + show_ntp_output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_SHOW_NTP) + match = re.search(ClockConsts.REGEX_NTP_POLLING_TIME, show_ntp_output) + if match: + polling_time_seconds = int(match.group(1)) + else: + logging.info('Could not match the regex.\nPattern: "{}"\nShow ntp output string: "{}"' + .format(ClockConsts.REGEX_NTP_POLLING_TIME, show_ntp_output)) + polling_time_seconds = ClockConsts.RANDOM_NUM + logging.info(f'Polling time (in seconds): {polling_time_seconds + 1}') + + logging.info('Wait for the sync') + time.sleep(polling_time_seconds) diff --git a/tests/clock/test_clock.py b/tests/clock/test_clock.py index 0606b2cdc07..865d7961449 100755 --- a/tests/clock/test_clock.py +++ b/tests/clock/test_clock.py @@ -112,7 +112,6 @@ def verify_and_parse_show_clock_output(show_clock_output): datetime_obj = dt.datetime.strptime(date_time_to_parse, '%a %d %b %Y %I:%M:%S %p') logging.info(f'Datetime object: "{datetime_obj}"\t|\tType: {type(datetime_obj)}') except ValueError: - logging.info(f'Show clock output is not valid.\nOutput: "{show_clock_output}"') pytest.fail(f'Show clock output is not valid.\nOutput: "{show_clock_output}"') with allure.step('Split output of show clock'): @@ -211,15 +210,10 @@ def select_random_date(): with allure.step('Select a random date'): start_date = dt.date.fromisoformat(ClockConsts.MIN_SYSTEM_DATE) end_date = dt.date.fromisoformat(ClockConsts.MAX_SYSTEM_DATE) - diff_days = (end_date - start_date).days - rand_num_of_days = random.randint(0, diff_days) - rand_date = start_date + dt.timedelta(days=rand_num_of_days) - rand_date_str = rand_date.strftime('%Y-%m-%d') - logging.info(f'Selected random date: "{rand_date_str}"') return rand_date_str @@ -301,9 +295,9 @@ def test_config_clock_timezone(duthosts, init_timezone): with allure.step(f'Set the new timezone "{new_timezone}"'): output = ClockUtils.run_cmd(duthosts, ClockConsts.CMD_CONFIG_CLOCK_TIMEZONE, new_timezone) - - with allure.step('Verify command success'): - assert output == ClockConsts.OUTPUT_CMD_SUCCESS, f'Expected: "{output}" == "{ClockConsts.OUTPUT_CMD_SUCCESS}"' + with allure.step('Verify command success'): + assert output == ClockConsts.OUTPUT_CMD_SUCCESS, \ + f'Expected: "{output}" == "{ClockConsts.OUTPUT_CMD_SUCCESS}"' with allure.step(f'Verify timezone changed to "{new_timezone}"'): ClockUtils.verify_timezone_value(duthosts, expected_tz_name=new_timezone) From 6069defd3938bdee8d2363117b40583f3de9a562 Mon Sep 17 00:00:00 2001 From: Alon Navarro Date: Mon, 7 Aug 2023 15:01:24 +0300 Subject: [PATCH 23/24] remove unnecessary constants --- tests/clock/test_clock.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tests/clock/test_clock.py b/tests/clock/test_clock.py index 865d7961449..ff8b6e38d3e 100755 --- a/tests/clock/test_clock.py +++ b/tests/clock/test_clock.py @@ -18,9 +18,6 @@ class ClockConsts: - STDOUT = "stdout" - STDERR = "stderr" - DATE = "date" TIME = "time" TIMEZONE = "timezone" @@ -78,10 +75,10 @@ def run_cmd(duthosts, cmd, param=''): logging.info(f'Actual command to run: "{cmd_to_run}"') try: - cmd_output = duthosts.command(cmd_to_run)[dut_hostname][ClockConsts.STDOUT] + cmd_output = duthosts.command(cmd_to_run)[dut_hostname]["stdout"] except RunAnsibleModuleFail as cmd_err: - output = cmd_err.results[ClockConsts.STDOUT] - err = cmd_err.results[ClockConsts.STDERR] + output = cmd_err.results["stdout"] + err = cmd_err.results["stderr"] cmd_output = output if output else err logging.info(f'Command Error!\nError message: "{cmd_output}"') From 0c4ceaa89feebcf433b5ddea247d6b9125aa55ef Mon Sep 17 00:00:00 2001 From: Alon Navarro Date: Tue, 8 Aug 2023 13:15:45 +0300 Subject: [PATCH 24/24] make ntp server parameter be required --- tests/clock/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/clock/conftest.py b/tests/clock/conftest.py index 78a2916d9cb..23260ca99e5 100755 --- a/tests/clock/conftest.py +++ b/tests/clock/conftest.py @@ -7,7 +7,7 @@ def pytest_addoption(parser): - parser.addoption("--ntp_server", action="store", default=None, help="IP of NTP server to use") + parser.addoption("--ntp_server", action="store", default=None, required=True, help="IP of NTP server to use") @pytest.fixture(scope='session', autouse=True)