-
Notifications
You must be signed in to change notification settings - Fork 1k
Converted port_toggle test and continuous_link_flap test to pytest #2389
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
yxieca
merged 15 commits into
sonic-net:master
from
OleksandrKozodoi:port_toggle_to_pytest
Nov 5, 2020
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
284ba15
Convert port_toggle test to pytest
OleksandrKozodoi 3913a1d
Add teardown fixture for port toggle test
OleksandrKozodoi 127ec7e
Change port toggle tool based on port toggle test
OleksandrKozodoi a54e6db
Move test_link_flap.py to tests/platform_tests/link_flap/
OleksandrKozodoi 7408c73
Convert continuous_link_flap test to pytest
OleksandrKozodoi 0e45adc
Remove extra line
OleksandrKozodoi 6372b4e
Remove % in comment
OleksandrKozodoi a83b5a3
Remove extra line
OleksandrKozodoi 699b6cf
Corrected minor typo in link_flap/conftest.py file
OleksandrKozodoi 731a212
Added wait_until to places where waiting is necessary
OleksandrKozodoi f3104de
Added topo marker for cont link flap test
OleksandrKozodoi 2ee3670
Combine pytest assert with wait_until in link flap test
OleksandrKozodoi cfd0655
Added changes of #2411
OleksandrKozodoi 790231b
Added changes #2427 to link_flap test
OleksandrKozodoi fdde9e9
Added check bgp routes to link flap utils
OleksandrKozodoi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,48 +1,70 @@ | ||
| """ | ||
| Tool used for shutdown/startup port on the DUT. | ||
| """ | ||
|
|
||
| import time | ||
| import logging | ||
| import pprint | ||
|
|
||
| from tests.common.helpers.assertions import pytest_assert | ||
| from tests.platform_tests.link_flap.link_flap_utils import watch_system_status | ||
| from tests.common.utilities import wait_until | ||
|
|
||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| def port_toggle(duthost, ports=None, wait=60, wait_after_ports_up=60): | ||
| def port_toggle(duthost, ports=None, wait=60, wait_after_ports_up=60, watch=False): | ||
| """ | ||
| Toggle ports on DUT | ||
| :param duthost: DUT host object | ||
| :param ports: specify list of ports, None if toggle all ports | ||
| :param wait: time to wait for interface to become up | ||
| :param wait_after_ports_up: time to wait after interfaces become up | ||
| :return: | ||
| Toggle ports on DUT. | ||
|
|
||
| Args: | ||
| duthost: DUT host object | ||
| ports: Specify list of ports, None if toggle all ports | ||
| wait: Time to wait for interface to become up | ||
| wait_after_ports_up: Time to wait after interfaces become up | ||
| watch: Logging system state | ||
| """ | ||
|
|
||
| def __check_interface_state(state='up'): | ||
| """ | ||
| Check interfaces status | ||
|
|
||
| Args: | ||
| state: state of DUT's interface | ||
| """ | ||
| ports_down = duthost.interface_facts(up_ports=ports)['ansible_facts']['ansible_interface_link_down_ports'] | ||
|
|
||
| if 'down' in state: | ||
| return len(ports_down) == len(ports) | ||
| else: | ||
| return len(ports_down) == 0 | ||
|
|
||
| if ports is None: | ||
| logger.debug('ports is None, toggling all minigraph ports') | ||
| mg_facts = duthost.minigraph_facts(host=duthost.hostname)['ansible_facts'] | ||
| ports = mg_facts['minigraph_ports'].keys() | ||
|
|
||
| logger.info('toggling ports:\n{}'.format(pprint.pformat(ports))) | ||
| logger.info('toggling ports:\n%s', pprint.pformat(ports)) | ||
|
|
||
| for port in ports: | ||
| duthost.command('config interface shutdown {}'.format(port)) | ||
| if watch: | ||
| time.sleep(1) | ||
| watch_system_status(duthost) | ||
|
|
||
| # verify all interfaces are up | ||
| ports_down = duthost.interface_facts(up_ports=ports)['ansible_facts']['ansible_interface_link_down_ports'] | ||
| assert len(ports_down) == len(ports) | ||
| # verify all interfaces are down | ||
| pytest_assert(wait_until(3, 1, __check_interface_state, 'down'), | ||
| "dut ports {} didn't go down as expected" | ||
| .format(list(set(ports).difference(set(duthost.interface_facts(up_ports=ports)['ansible_facts']['ansible_interface_link_down_ports']))))) | ||
|
|
||
| for port in ports: | ||
| duthost.command('config interface startup {}'.format(port)) | ||
|
|
||
| logger.info('waiting for ports to become up') | ||
|
|
||
| start = time.time() | ||
| ports_down = duthost.interface_facts(up_ports=ports)['ansible_facts']['ansible_interface_link_down_ports'] | ||
| while time.time() - start < wait: | ||
| ports_down = duthost.interface_facts(up_ports=ports)['ansible_facts']['ansible_interface_link_down_ports'] | ||
| logger.info('retry, down ports:\n{}'.format(pprint.pformat(ports_down))) | ||
| if len(ports_down) == 0: | ||
| break | ||
|
|
||
| assert len(ports_down) == 0 | ||
| pytest_assert(wait_until(wait, 1, __check_interface_state), | ||
| "dut ports {} didn't go up as expected".format(duthost.interface_facts(up_ports=ports)['ansible_facts']['ansible_interface_link_down_ports'])) | ||
|
|
||
| logger.info('wait {} seconds for system to startup'.format(wait_after_ports_up)) | ||
| logger.info('wait %d seconds for system to startup', wait_after_ports_up) | ||
| time.sleep(wait_after_ports_up) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| """ | ||
| Pytest configuration used by the link flap tests. | ||
|
|
||
| Teardowns used by the link flap tests. | ||
| """ | ||
|
|
||
| import time | ||
|
|
||
| import pytest | ||
|
|
||
| from tests.platform_tests.link_flap.link_flap_utils import build_test_candidates | ||
| from tests.common.helpers.dut_ports import decode_dut_port_name | ||
|
|
||
| def pytest_addoption(parser): | ||
| """ | ||
| Adds options to pytest that are used by the Link flap tests. | ||
| """ | ||
|
|
||
| parser.addoption( | ||
| "--orch_cpu_threshold", | ||
| action="store", | ||
| type=int, | ||
| default=10, | ||
| help="Orchagent CPU threshold", | ||
| ) | ||
|
|
||
|
|
||
| @pytest.fixture() | ||
| def bring_up_fanout_interfaces(request, all_ports, duthosts, fanouthosts): | ||
| """ | ||
| Bring up outer interfaces on the DUT. | ||
|
|
||
| Args: | ||
| request: pytest request object | ||
| duthost: Fixture for interacting with the DUT. | ||
| fanouthosts: Fixture for interacting with the fanouts. | ||
| """ | ||
| yield | ||
| if request.node.rep_call.failed: | ||
| dutname, portname = decode_dut_port_name(all_ports) | ||
|
|
||
| for dut in duthosts: | ||
| if dutname == 'unknown' or dutname == dut.hostname: | ||
| candidates = build_test_candidates(dut, fanouthosts, portname) | ||
| for _, fanout, fanout_port in candidates: | ||
| fanout.no_shutdown(fanout_port) | ||
|
|
||
| time.sleep(60) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,188 @@ | ||
| """ | ||
| Test utils used by the link flap tests. | ||
| """ | ||
| import time | ||
| import logging | ||
|
|
||
| from tests.common.platform.device_utils import fanout_switch_port_lookup | ||
| from tests.common.utilities import wait_until | ||
| from tests.common.helpers.assertions import pytest_assert | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
| def __get_dut_if_status(dut, ifname=None): | ||
| """ | ||
| Get interface status on the DUT. | ||
|
|
||
| Args: | ||
| dut: DUT host object | ||
| ifname: Interface of DUT | ||
| exp_state: State of DUT's port ('up' or 'down') | ||
| verbose: Logging port state. | ||
|
|
||
| Returns: | ||
| Interface state | ||
| """ | ||
| if not ifname: | ||
| status = dut.show_interface(command='status')['ansible_facts']['int_status'] | ||
| else: | ||
| status = dut.show_interface(command='status', interfaces=[ifname])['ansible_facts']['int_status'] | ||
| return status | ||
|
|
||
|
|
||
| def __check_if_status(dut, dut_port, exp_state, verbose=False): | ||
| """ | ||
| Check interface status on the DUT. | ||
|
|
||
| Args: | ||
| dut: DUT host object | ||
| dut_port: Port of DUT | ||
| exp_state: State of DUT's port ('up' or 'down') | ||
| verbose: Logging port state. | ||
|
|
||
| Returns: | ||
| Bool value which confirm port state | ||
| """ | ||
| status = __get_dut_if_status(dut, dut_port)[dut_port] | ||
| if verbose: | ||
| logger.debug("Interface status : %s", status) | ||
| return status['oper_state'] == exp_state | ||
|
|
||
|
|
||
| def __build_candidate_list(candidates, fanout, fanout_port, dut_port, status): | ||
| """ | ||
| Add candidates to list for link flap test. | ||
|
|
||
| Args: | ||
| candidates: List of tuple with DUT's port, | ||
| fanout port and fanout | ||
| fanout: Fanout host object | ||
| fanout_port: Port of fanout | ||
| dut_port: Port of DUT | ||
| completeness_level: Completeness level. | ||
|
|
||
| Returns: | ||
| A list of tuple with DUT's port, fanout port | ||
| and fanout | ||
| """ | ||
| if not fanout or not fanout_port: | ||
| logger.info("Skipping port {} that is not found in connection graph".format(dut_port)) | ||
| elif status[dut_port]['admin_state'] == 'down': | ||
| logger.info("Skipping port {} that is admin down".format(dut_port)) | ||
| else: | ||
| candidates.append((dut_port, fanout, fanout_port)) | ||
|
|
||
|
|
||
| def build_test_candidates(dut, fanouthosts, port, completeness_level=None): | ||
| """ | ||
| Find test candidates for link flap test. | ||
|
|
||
| Args: | ||
| dut: DUT host object | ||
| fanouthosts: List of fanout switch instances. | ||
| port: port | ||
| completeness_level: Completeness level. | ||
|
|
||
| Returns: | ||
| A list of tuple with DUT's port, fanout port | ||
| and fanout | ||
| """ | ||
| candidates = [] | ||
|
|
||
| if port != 'unknown': | ||
| status = __get_dut_if_status(dut, port) | ||
| fanout, fanout_port = fanout_switch_port_lookup(fanouthosts, dut.hostname, port) | ||
| __build_candidate_list(candidates, fanout, fanout_port, port, status) | ||
| else: | ||
| # Build the full list | ||
| logger.warning("Failed to get ports enumerated as parameter. Fall back to test all ports") | ||
| status = __get_dut_if_status(dut) | ||
|
|
||
| for dut_port in status.keys(): | ||
| fanout, fanout_port = fanout_switch_port_lookup(fanouthosts, dut.hostname, dut_port) | ||
| __build_candidate_list(candidates, fanout, fanout_port, dut_port, status) | ||
|
|
||
| if completeness_level == 'debug': | ||
| candidates = random.sample(candidates, 1) | ||
|
|
||
| return candidates | ||
|
|
||
|
|
||
| def toggle_one_link(dut, dut_port, fanout, fanout_port, watch=False): | ||
| """ | ||
| Toggle one link on the fanout. | ||
|
|
||
| Args: | ||
| dut: DUT host object | ||
| dut_port: Port of DUT | ||
| fanout: Fanout host object | ||
| fanout_port: Port of fanout | ||
| watch: Logging system state | ||
| """ | ||
| logger.info("Testing link flap on %s", dut_port) | ||
|
|
||
| pytest_assert(__check_if_status(dut, dut_port, 'up', verbose=True), "Fail: dut port {}: link operational down".format(dut_port)) | ||
|
|
||
| logger.info("Shutting down fanout switch %s port %s connecting to %s", fanout.hostname, fanout_port, dut_port) | ||
| fanout.shutdown(fanout_port) | ||
| pytest_assert(wait_until(30, 1, __check_if_status, dut, dut_port, 'down', True), "dut port {} didn't go down as expected".format(dut_port)) | ||
|
|
||
| if watch: | ||
| time.sleep(1) | ||
| watch_system_status(dut) | ||
|
|
||
| logger.info("Bring up fanout switch %s port %s connecting to %s", fanout.hostname, fanout_port, dut_port) | ||
| fanout.no_shutdown(fanout_port) | ||
| pytest_assert(wait_until(30, 1, __check_if_status, dut, dut_port, 'up', True), "dut port {} didn't go up as expected".format(dut_port)) | ||
|
|
||
|
|
||
| def watch_system_status(dut): | ||
| """ | ||
| Watch DUT's system status | ||
|
|
||
| Args: | ||
| dut: DUT host object | ||
| """ | ||
| # Watch memory status | ||
| memory_output = dut.shell("show system-memory")["stdout"] | ||
| logger.info("Memory Status: %s", memory_output) | ||
|
|
||
| # Watch orchagent CPU utilization | ||
| orch_cpu = dut.shell("show processes cpu | grep orchagent | awk '{print $9}'")["stdout"] | ||
| logger.info("Orchagent CPU Util: %s", orch_cpu) | ||
|
|
||
| # Watch Redis Memory | ||
| redis_memory = dut.shell("redis-cli info memory | grep used_memory_human")["stdout"] | ||
| logger.info("Redis Memory: %s", redis_memory) | ||
|
|
||
|
|
||
| def check_orch_cpu_utilization(dut, orch_cpu_threshold): | ||
| """ | ||
| Compare orchagent CPU utilization | ||
|
|
||
| Args: | ||
| dut: DUT host object | ||
| orch_cpu_threshold: orch cpu threshold | ||
| """ | ||
| orch_cpu = dut.shell("show processes cpu | grep orchagent | awk '{print $9}'")["stdout"] | ||
| return int(float(orch_cpu)) < orch_cpu_threshold | ||
|
|
||
|
|
||
| def check_bgp_routes(dut, start_time_ip_route_counts, ipv4=False): | ||
| """ | ||
| Make Sure all ip routes are relearned with jitter of ~5 | ||
|
|
||
| Args: | ||
| dut: DUT host object | ||
| start_time_ip_route_counts: IP route counts at start | ||
| ipv4: Version of IP | ||
| """ | ||
| if ipv4: | ||
| end_time_ip_route_counts = dut.shell("show ip route summary | grep Total | awk '{print $2}'")["stdout"] | ||
| logger.info("IPv4 routes at end: %s", end_time_ip_route_counts) | ||
| else: | ||
| end_time_ip_route_counts = dut.shell("show ipv6 route summary | grep Total | awk '{print $2}'")["stdout"] | ||
| logger.info("IPv6 routes at end: %s", end_time_ip_route_counts) | ||
|
|
||
| incr_ip_route_counts = abs(int(float(start_time_ip_route_counts)) - int(float(end_time_ip_route_counts))) | ||
| return incr_ip_route_counts < 5 |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.