From: selias Date: Tue, 13 Sep 2016 14:51:37 +0000 (+0200) Subject: CSIT-405: Honeycomb test update and cleanup X-Git-Url: https://gerrit.fd.io/r/gitweb?p=csit.git;a=commitdiff_plain;h=19c91adadd57bfc4e7514993b2a711a826d52e04 CSIT-405: Honeycomb test update and cleanup - update suite setup and constants to allow test runs again - cleanup basic interface keywords - cleanup L2-fib test data - add "continue on failure" keyword to some partially failing tests - add teardown to all suites, restarts honeycomb if suite had test failures - fix minor PEP-8 violations in Topology.py Change-Id: Ic5b434af71f77855f81461b280299b8318932c5a Signed-off-by: selias --- diff --git a/resources/libraries/python/constants.py b/resources/libraries/python/constants.py index 6e71eb0110..2978f46759 100644 --- a/resources/libraries/python/constants.py +++ b/resources/libraries/python/constants.py @@ -26,7 +26,10 @@ class Constants(object): VAT_BIN_NAME = 'vpp_api_test' # Honeycomb directory location at topology nodes: - REMOTE_HC_DIR = '/opt/honeycomb/vpp-integration-karaf-1.0.0-SNAPSHOT' + REMOTE_HC_DIR = '/opt/honeycomb' + + # Honeycomb persistence files location + REMOTE_HC_PERSIST = '/var/lib/honeycomb/persist' # Honeycomb templates location RESOURCES_TPL_HC = 'resources/templates/honeycomb' diff --git a/resources/libraries/python/honeycomb/HcPersistence.py b/resources/libraries/python/honeycomb/HcPersistence.py index 4d192525d8..3bbc52fa91 100644 --- a/resources/libraries/python/honeycomb/HcPersistence.py +++ b/resources/libraries/python/honeycomb/HcPersistence.py @@ -40,7 +40,7 @@ class HcPersistence(object): :type nodes: list :raises HoneycombError: If persisted configuration could not be removed. """ - cmd = "rm {0}/data/persistence/honeycomb/*".format(Const.REMOTE_HC_DIR) + cmd = "rm -rf {}/*".format(Const.REMOTE_HC_PERSIST) for node in nodes: if node['type'] == NodeType.DUT: ssh = SSH() @@ -60,7 +60,7 @@ class HcPersistence(object): @staticmethod def modify_persistence_files(node, find, replace): - """Searches contents of persistence file config.json for the provided + """Searches contents of persistence file data.json for the provided string, and replaces all occurrences with another string. :param node: Honeycomb node. @@ -74,8 +74,7 @@ class HcPersistence(object): """ argument = "\"s/{0}/{1}/g\"".format(find, replace) - path = "{0}/etc/opendaylight/honeycomb/config.json".format( - Const.REMOTE_HC_DIR) + path = "{0}/config/data.json".format(Const.REMOTE_HC_PERSIST) command = "sed -i {0} {1}".format(argument, path) ssh = SSH() diff --git a/resources/libraries/python/honeycomb/HoneycombSetup.py b/resources/libraries/python/honeycomb/HoneycombSetup.py index 04af9a5a8b..b8c47fac03 100644 --- a/resources/libraries/python/honeycomb/HoneycombSetup.py +++ b/resources/libraries/python/honeycomb/HoneycombSetup.py @@ -58,7 +58,7 @@ class HoneycombSetup(object): logger.console("\nStarting Honeycomb service ...") - cmd = "{0}/bin/start".format(Const.REMOTE_HC_DIR) + cmd = "sudo service honeycomb start" for node in nodes: if node['type'] == NodeType.DUT: @@ -86,7 +86,7 @@ class HoneycombSetup(object): """ logger.console("\nShutting down Honeycomb service ...") - cmd = "{0}/bin/stop".format(Const.REMOTE_HC_DIR) + cmd = "sudo service honeycomb stop" errors = [] for node in nodes: @@ -143,6 +143,13 @@ class HoneycombSetup(object): else: raise HoneycombError('Unexpected return code: {0}.'. format(status_code)) + + status_code, _ = HcUtil.get_honeycomb_data( + node, "config_vpp_interfaces") + if status_code != HTTPCodes.OK: + raise HoneycombError('Honeycomb on node {0} running but ' + 'not yet ready.'.format(node['host']), + enable_logging=False) return True @staticmethod @@ -157,7 +164,7 @@ class HoneycombSetup(object): :return: True if all GETs fail to connect. :rtype bool """ - cmd = "ps -ef | grep -v grep | grep karaf" + cmd = "ps -ef | grep -v grep | grep honeycomb" for node in nodes: if node['type'] == NodeType.DUT: try: @@ -190,6 +197,33 @@ class HoneycombSetup(object): format(node['host'])) return True + @staticmethod + def configure_unsecured_access(*nodes): + """Configure Honeycomb to allow restconf requests through insecure HTTP + used by tests. By default this is only allowed for localhost. + + :param nodes: All nodes in test topology. + :type nodes: dict + :raises HoneycombError: If the configuration could not be changed. + """ + # TODO: Modify tests to use HTTPS instead. + + find = "restconf-binding-address" + replace = '\\"restconf-binding-address\\": \\"0.0.0.0\\",' + + argument = '"/{0}/c\\ {1}"'.format(find, replace) + path = "{0}/config/honeycomb.json".format(Const.REMOTE_HC_DIR) + command = "sed -i {0} {1}".format(argument, path) + + ssh = SSH() + for node in nodes: + if node['type'] == NodeType.DUT: + ssh.connect(node) + (ret_code, _, stderr) = ssh.exec_command_sudo(command) + if ret_code != 0: + raise HoneycombError("Failed to modify configuration on " + "node {0}, {1}".format(node, stderr)) + @staticmethod def print_environment(nodes): """Print information about the nodes to log. The information is defined @@ -239,3 +273,4 @@ class HoneycombSetup(object): ssh = SSH() ssh.connect(node) ssh.exec_command_sudo(cmd) + diff --git a/resources/libraries/python/honeycomb/HoneycombUtil.py b/resources/libraries/python/honeycomb/HoneycombUtil.py index 8f1392c972..2b8e28a5a6 100644 --- a/resources/libraries/python/honeycomb/HoneycombUtil.py +++ b/resources/libraries/python/honeycomb/HoneycombUtil.py @@ -86,7 +86,6 @@ class HoneycombError(Exception): self._msg = "{0}: {1}".format(self.__class__.__name__, msg) self._details = details if enable_logging: - logger.error(self._msg) logger.debug(self._details) def __repr__(self): diff --git a/resources/libraries/python/topology.py b/resources/libraries/python/topology.py index a5c67d313c..c02991fbde 100644 --- a/resources/libraries/python/topology.py +++ b/resources/libraries/python/topology.py @@ -278,11 +278,12 @@ class Topology(object): :return: Interface name of the interface connected to the given link. :rtype: str """ - return Topology._get_interface_by_key_value(node, "vpp_sw_index", sw_index) + return Topology._get_interface_by_key_value(node, "vpp_sw_index", + sw_index) @staticmethod def get_interface_sw_index(node, iface_key): - """Get VPP sw_if_index for the interface. + """Get VPP sw_if_index for the interface using interface key. :param node: Node to get interface sw_if_index on. :param iface_key: Interface key from topology file, or sw_index. @@ -299,6 +300,26 @@ class Topology(object): except (KeyError, ValueError): return None + @staticmethod + def get_interface_sw_index_by_name(node, iface_name): + """Get VPP sw_if_index for the interface using interface name. + + :param node: Node to get interface sw_if_index on. + :param iface_name: Interface name. + :type node: dict + :type iface_name: str + :return: Return sw_if_index or None if not found. + :raises TypeError: If provided interface name is not a string. + """ + try: + if isinstance(iface_name, basestring): + iface_key = Topology.get_interface_by_name(node, iface_name) + return node['interfaces'][iface_key].get('vpp_sw_index') + else: + raise TypeError("Interface name must be a string.") + except (KeyError, ValueError): + return None + @staticmethod def get_interface_mtu(node, iface_key): """Get interface MTU. @@ -514,7 +535,7 @@ class Topology(object): if filt == interface['model']: link_names.append(interface['link']) elif (filter_list is not None) and ('model' not in interface): - logger.trace("Cannot apply filter on interface: {}" \ + logger.trace("Cannot apply filter on interface: {}" .format(str(interface))) else: link_names.append(interface['link']) @@ -534,8 +555,8 @@ class Topology(object): :param filter_list_node2: Link filter criteria for node2. :type node1: dict :type node2: dict - :type filter_list1: list of strings - :type filter_list2: list of strings + :type filter_list_node1: list of strings + :type filter_list_node2: list of strings :return: List of strings that represent connecting link names. :rtype: list """ @@ -578,7 +599,8 @@ class Topology(object): else: return connecting_links[0] - @keyword('Get egress interfaces name on "${node1}" for link with "${node2}"') + @keyword('Get egress interfaces name on "${node1}" for link with ' + '"${node2}"') def get_egress_interfaces_name_for_nodes(self, node1, node2): """Get egress interfaces on node1 for link with node2. diff --git a/resources/libraries/robot/honeycomb/honeycomb.robot b/resources/libraries/robot/honeycomb/honeycomb.robot index c04bd23a57..698b20f83f 100644 --- a/resources/libraries/robot/honeycomb/honeycomb.robot +++ b/resources/libraries/robot/honeycomb/honeycomb.robot @@ -14,6 +14,7 @@ *** Settings *** | Library | resources/libraries/python/honeycomb/HoneycombSetup.py | Library | resources/libraries/python/honeycomb/HoneycombUtil.py +| Library | resources/libraries/python/honeycomb/HcPersistence.py *** Keywords *** | Setup Honeycomb service on DUTs @@ -36,7 +37,7 @@ | | ... | | [Arguments] | @{duts} | | Start honeycomb on DUTs | @{duts} -| | Wait until keyword succeeds | 4min | 20sec +| | Wait until keyword succeeds | 1min | 10sec | | ... | Check honeycomb startup state | @{duts} | Stop honeycomb service on DUTs @@ -58,7 +59,7 @@ | | ... | | [Arguments] | @{duts} | | Stop honeycomb on DUTs | @{duts} -| | Wait until keyword succeeds | 2m | 10s +| | Wait until keyword succeeds | 30sec | 5sec | | ... | Check honeycomb shutdown state | @{duts} | Clear persisted Honeycomb configuration @@ -71,4 +72,21 @@ | | ... | | ... | \| Clear persisted Honeycomb configuration \| ${nodes['DUT1']} \| | | [Arguments] | @{duts} -| | Clear persisted Honeycomb config | @{duts} \ No newline at end of file +| | Clear persisted Honeycomb config | @{duts} + +| Restart Honeycomb and VPP and clear persisted configuration +| | [Documentation] | Restarts Honeycomb and VPP with default configuration. +| | ... +| | ... | *Arguments:* +| | ... | - node - information about a DUT node. Type: dictionary +| | ... +| | ... | *Example:* +| | ... +| | ... | \| Restart Honeycomb and VPP and clear persisted configuration \ +| | ... | \| ${nodes['DUT1']} \| +| | [Arguments] | ${node} +| | Log | Performing clean restart of Honeycomb and VPP. | console=True +| | Stop Honeycomb service on DUTs | ${node} +| | Clear persisted Honeycomb configuration | ${node} +| | Setup DUT | ${node} +| | Setup Honeycomb service on DUTs | ${node} \ No newline at end of file diff --git a/resources/libraries/robot/honeycomb/interfaces.robot b/resources/libraries/robot/honeycomb/interfaces.robot index 81b5d82048..f94d03d7d4 100644 --- a/resources/libraries/robot/honeycomb/interfaces.robot +++ b/resources/libraries/robot/honeycomb/interfaces.robot @@ -190,7 +190,7 @@ | | ... | ${api_data['ietf-ip:ipv4']['neighbor'][0]['link-layer-address']} | | :FOR | ${key} | IN | @{settings.keys()} | | | Should be equal -| | | ... | ${settings['{key']} | ${api_data['ietf-ip:ipv4']['{$key}']} +| | | ... | ${settings['${key}']} | ${api_data['ietf-ip:ipv4']['${key}']} | IPv4 config from VAT should be | | [Documentation] | Retrieves interface ipv4 configuration through VAT and\ @@ -209,7 +209,6 @@ | | [Arguments] | ${node} | ${interface} | ${address} | ${netmask} | | ${vpp_data}= | interfaceCLI.VPP get interface ip addresses | | ... | ${node} | ${interface} | ipv4 -#TODO: update based on resolution of bug https://jira.fd.io/browse/VPP-132 | | Should be equal | ${vpp_data[0]['ip']} | ${address} | | Should be equal | ${vpp_data[0]['netmask']} | ${netmask} diff --git a/resources/libraries/robot/honeycomb/persistence.robot b/resources/libraries/robot/honeycomb/persistence.robot index aacf560f1d..6d2cc1f2e3 100644 --- a/resources/libraries/robot/honeycomb/persistence.robot +++ b/resources/libraries/robot/honeycomb/persistence.robot @@ -14,7 +14,7 @@ *** Settings *** | Library | resources.libraries.python.honeycomb.HcAPIKwInterfaces.InterfaceKeywords | ... | WITH NAME | InterfaceAPI -| Library | resources.libraries.python.honeycomb.HcPersistence +| Library | resources/libraries/python/honeycomb/HcPersistence.py | Resource | resources/libraries/robot/honeycomb/honeycomb.robot | Resource | resources/libraries/robot/honeycomb/interfaces.robot | Resource | resources/libraries/robot/honeycomb/vxlan.robot diff --git a/resources/libraries/robot/honeycomb/vxlan_gpe.robot b/resources/libraries/robot/honeycomb/vxlan_gpe.robot index 364a23228c..ef20ed946c 100644 --- a/resources/libraries/robot/honeycomb/vxlan_gpe.robot +++ b/resources/libraries/robot/honeycomb/vxlan_gpe.robot @@ -153,9 +153,25 @@ | | Should be equal as strings | | ... | ${api_data['if-index']} | ${sw_if_index} +| VxLAN GPE configuration from Honeycomb should be empty +| | [Documentation] | Uses Honeycomb API to get operational data about\ +| | ... | the given interface and expects to fail. +| | ... +| | ... | *Arguments:* +| | ... | - node - information about a DUT node. Type: dictionary +| | ... +| | ... | *Example:* +| | ... | \| VxLAN GPE configuration from Honeycomb should be empty\ +| | ... | \| ${nodes['DUT1']} \| vxlan_gpe_tunnel0 \| +| | ... +| | [Arguments] | ${node} | ${interface} +| | ... +| | ${api_data}= | interfaceAPI.Get interface oper data | ${node} | ${interface} +| | Should be empty | ${api_data} + | VxLAN GPE configuration from VAT should be empty | | [Documentation] | Uses VAT to get operational data about the given\ -| | ... | interface and expects empty dictionary. +| | ... | interface and expects an empty dictionary. | | ... | | ... | *Arguments:* | | ... | - node - information about a DUT node. Type: dictionary diff --git a/resources/test_data/honeycomb/l2_fib.py b/resources/test_data/honeycomb/l2_fib.py index b06193ad1d..d1600fc46d 100644 --- a/resources/test_data/honeycomb/l2_fib.py +++ b/resources/test_data/honeycomb/l2_fib.py @@ -13,130 +13,160 @@ """Test variables for Honeycomb L2 FIB test suite.""" -# Bridge domain name. -bd_name = 'test-l2-bd' -bd_index = 1 - -# Bridge domain settings used while creating a test bridge domain. -bd_settings = { - 'flood': True, - 'forward': True, - 'learn': True, - 'unknown-unicast-flood': True, - 'arp-termination': True -} - -# Bridge domain configuration used while adding the bridge domain to an -# interface. -if_bd_settings = { - 'bridge-domain': bd_name, - 'split-horizon-group': 1, - 'bridged-virtual-interface': False -} - -# Add L2 FIB entry (forward). -# Configuration data: -l2_fib_forward_cfg = { - "phys-address": "aa:bb:cc:dd:ee:ff", - "outgoing-interface": "GigabitEthernet0/8/0", - "action": "l2-fib-forward" -} - -# Expected operational data: -l2_fib_forward_oper = { - "phys-address": "aa:bb:cc:dd:ee:ff", - "outgoing-interface": "GigabitEthernet0/8/0", - "bridged-virtual-interface": False, - "action": "v3po:l2-fib-forward", - "static-config": False -} - -# Expected VAT data: -l2_fib_forward_vat = { - "mac": int("".join(l2_fib_forward_oper["phys-address"].split(':')), 16), - "static_mac": 0, - "filter_mac": 0, - "bvi_mac": 0 - } - -# Add L2 FIB entry (static, forward). -# Configuration data: -l2_fib_static_forward_cfg = { - "phys-address": "22:22:33:44:55:66", - "outgoing-interface": "GigabitEthernet0/8/0", - "static-config": True, - "action": "l2-fib-forward" -} - -# Expected operational data: -l2_fib_static_forward_oper = { - "phys-address": "22:22:33:44:55:66", - "outgoing-interface": "GigabitEthernet0/8/0", - "bridged-virtual-interface": False, - "action": "v3po:l2-fib-forward", - "static-config": True -} - -# Expected VAT data: -l2_fib_static_forward_vat = { - "mac": int("".join(l2_fib_static_forward_oper["phys-address"]. - split(':')), 16), - "sw_if_index": 5, - "static_mac": 1, - "filter_mac": 0, - "bvi_mac": 0 -} - -# Add L2 FIB entry (filter). -# Configuration data: -l2_fib_filter_cfg = { - "phys-address": "00:01:02:03:04:05", - "outgoing-interface": "GigabitEthernet0/8/0", - "static-config": True, - "action": "l2-fib-filter" -} - -# Expected operational data: -l2_fib_filter_oper = { - "phys-address": "00:01:02:03:04:05", - "outgoing-interface": "GigabitEthernet0/8/0", - "bridged-virtual-interface": False, - "action": "v3po:l2-fib-filter", - "static-config": True -} - -# Expected VAT data: -l2_fib_filter_vat = { - "mac": int("".join(l2_fib_filter_oper["phys-address"].split(':')), 16), - "sw_if_index": 5, - "static_mac": 1, - "filter_mac": 1, - "bvi_mac": 0 -} - -# WRONG configuration data - Add L2 FIB entry. -l2_fib_forward_cfg_wrong_mac = { - "phys-address": "WRONG-MAC", - "outgoing-interface": "GigabitEthernet0/8/0", - "action": "l2-fib-forward" -} - -l2_fib_forward_cfg_wrong_if = { - "phys-address": "aa:bb:cc:dd:ee:ff", - "outgoing-interface": "WRONG-INTERFACE", - "action": "l2-fib-forward" -} - -l2_fib_forward_cfg_wrong_action = { - "phys-address": "aa:bb:cc:dd:ee:ff", - "outgoing-interface": "GigabitEthernet0/8/0", - "action": "WRONG-ACTION" -} - -# Modify L2 FIB entry (forward). -# Configuration data: -l2_fib_forward_modified_cfg = { - "phys-address": "aa:bb:cc:dd:ee:ff", - "outgoing-interface": "GigabitEthernet0/9/0", - "action": "l2-fib-forward" -} +from resources.libraries.python.topology import Topology + + +def get_variables(node, interface, interface2): + """Creates and returns dictionary of test variables. + + :param node: A Honeycomb node. + :param interface: Name of an interface on the specified node. + :param interface: Name of another interface on the specified node. + :type node: dict + :type interface: str + :type interface2: str + :return: Dictionary of test variables. + :rtype: dict + """ + # Interface sw_if_index + sw_if_index = Topology.get_interface_sw_index_by_name(node, interface) + sw_if_index2 = Topology.get_interface_sw_index_by_name(node, interface2) + + # Bridge domain name. + bd_name = 'test-l2-bd' + + # L2 FIB MACs used in configuration. + notstatic = "aa:bb:cc:dd:ee:ff" + static = "22:22:33:44:55:66" + filtered = "00:01:02:03:04:05" + + variables = { + 'bd_name': bd_name, + # Bridge domain settings used while creating a test bridge domain. + 'bd_settings': { + 'flood': True, + 'forward': True, + 'learn': True, + 'unknown-unicast-flood': True, + 'arp-termination': True + }, + + # Index of created bridge domain. + 'bd_index': 1, + + # Bridge domain configuration used while adding the bridge domain to an + # interface. + 'if_bd_settings': { + 'bridge-domain': bd_name, + 'split-horizon-group': 1, + 'bridged-virtual-interface': False + }, + + # Add L2 FIB entry (forward). + # Configuration data: + 'l2_fib_forward_cfg': { + "phys-address": notstatic, + "outgoing-interface": interface, + "action": "l2-fib-forward" + }, + + # Expected operational data: + 'l2_fib_forward_oper': { + "phys-address": notstatic, + "outgoing-interface": interface, + "bridged-virtual-interface": False, + "action": "v3po:l2-fib-forward", + "static-config": False + }, + + # Expected VAT data: + 'l2_fib_forward_vat': { + "mac": int("".join(notstatic.split(':')), 16), + "sw_if_index": sw_if_index, + "static_mac": 0, + "filter_mac": 0, + "bvi_mac": 0 + }, + + # Add L2 FIB entry (static, forward). + # Configuration data: + 'l2_fib_static_forward_cfg': { + "phys-address": static, + "outgoing-interface": interface, + "static-config": True, + "action": "l2-fib-forward" + }, + + # Expected operational data: + 'l2_fib_static_forward_oper': { + "phys-address": static, + "outgoing-interface": interface, + "bridged-virtual-interface": False, + "action": "v3po:l2-fib-forward", + "static-config": True + }, + + # Expected VAT data: + 'l2_fib_static_forward_vat': { + "mac": int("".join(static.split(':')), 16), + "sw_if_index": sw_if_index, + "static_mac": 1, + "filter_mac": 0, + "bvi_mac": 0 + }, + + # Add L2 FIB entry (filter). + # Configuration data: + 'l2_fib_filter_cfg': { + "phys-address": filtered, + "outgoing-interface": interface, + "static-config": True, + "action": "l2-fib-filter" + }, + + # Expected operational data: + 'l2_fib_filter_oper': { + "phys-address": filtered, + "outgoing-interface": interface, + "bridged-virtual-interface": False, + "action": "v3po:l2-fib-filter", + "static-config": True + }, + + # Expected VAT data: + 'l2_fib_filter_vat': { + "mac": int("".join(filtered.split(':')), 16), + "sw_if_index": sw_if_index, + "static_mac": 1, + "filter_mac": 1, + "bvi_mac": 0 + }, + + # WRONG configuration data - Add L2 FIB entry. + 'l2_fib_forward_cfg_wrong_mac': { + "phys-address": "WRONG-MAC", + "outgoing-interface": interface, + "action": "l2-fib-forward" + }, + + 'l2_fib_forward_cfg_wrong_if': { + "phys-address": notstatic, + "outgoing-interface": "WRONG-INTERFACE", + "action": "l2-fib-forward" + }, + + 'l2_fib_forward_cfg_wrong_action': { + "phys-address": notstatic, + "outgoing-interface": interface, + "action": "WRONG-ACTION" + }, + + # Modify L2 FIB entry (forward). + # Configuration data: + 'l2_fib_forward_modified_cfg': { + "phys-address": notstatic, + "outgoing-interface": sw_if_index2, + "action": "l2-fib-forward" + } + } + return variables diff --git a/tests/func/honeycomb/010_interface_management.robot b/tests/func/honeycomb/010_interface_management.robot index e9798167c7..2c639c5c6a 100644 --- a/tests/func/honeycomb/010_interface_management.robot +++ b/tests/func/honeycomb/010_interface_management.robot @@ -33,16 +33,20 @@ *** Settings *** | Resource | resources/libraries/robot/default.robot | Resource | resources/libraries/robot/honeycomb/interfaces.robot +| Resource | resources/libraries/robot/honeycomb/honeycomb.robot | Force Tags | honeycomb_sanity +| Suite Teardown | Run Keyword If Any Tests Failed +| | ... | Restart Honeycomb And VPP And Clear Persisted Configuration | ${node} | Documentation | *Honeycomb interface management test suite.* | ... | ... | Test suite uses the first interface of the first DUT node. *** Test Cases *** +# TODO: Remove "continue on failure" once VPP bugs (VPP-132, VPP-333) are fixed. | Honeycomb configures and reads interface state | | [Documentation] | Check if Honeycomb API can modify the admin state of\ | | ... | VPP interfaces. -| | Given Interface state is | ${node} | ${interface} | down +| | Given Interface State Is | ${node} | ${interface} | down | | When Honeycomb sets interface state | ${node} | ${interface} | up | | Then Interface state from Honeycomb should be | | ... | ${node} | ${interface} | up @@ -59,22 +63,26 @@ | | ... | ${ipv4_address} | ${ipv4_mask} | ${ipv4_settings} | | And Honeycomb adds interface ipv4 neighbor | | ... | ${node} | ${interface} | @{ipv4_neighbor} -| | Then IPv4 config from Honeycomb should be +| | Run Keyword And Continue On Failure +| | ... | Then IPv4 config from Honeycomb should be | | ... | ${node} | ${interface} | ${ipv4_address} | ${ipv4_prefix} | | ... | @{ipv4_neighbor} | ${ipv4_settings} -| | And IPv4 config from VAT should be +| | Run Keyword And Continue On Failure +| | ... | And IPv4 config from VAT should be | | ... | ${node} | ${interface} | ${ipv4_address} | ${ipv4_prefix} | Honeycomb removes ipv4 address from interface | | [Documentation] | Check if Honeycomb API can remove configured ipv4\ | | ... | addresses from interface. -| | Given IPv4 config from Honeycomb should be +| | Run Keyword And Continue On Failure +| | ... | Given IPv4 config from Honeycomb should be | | ... | ${node} | ${interface} | ${ipv4_address} | ${ipv4_prefix} | | ... | @{ipv4_neighbor} | ${ipv4_settings} -| | And IPv4 config from VAT should be +| | Run Keyword And Continue On Failure +| | ... | And IPv4 config from VAT should be | | ... | ${node} | ${interface} | ${ipv4_address} | ${ipv4_prefix} | | When Honeycomb removes interface ipv4 addresses | ${node} | ${interface} -| | Then IPv4 address from Honeycomb should be empty | ${node} |${interface} +| | Then IPv4 address from Honeycomb should be empty | ${node} | ${interface} | | And ipv4 address from VAT should be empty | ${node} | ${interface} | Honeycomb modifies interface configuration - ipv4 (prefix) @@ -87,11 +95,13 @@ | | ... | ${ipv4_settings} | | And Honeycomb adds interface ipv4 neighbor | | ... | ${node} | ${interface} | @{ipv4_neighbor} -| | Then IPv4 config from Honeycomb should be +| | Run Keyword And Continue On Failure +| | ... | Then IPv4 config from Honeycomb should be | | ... | ${node} | ${interface} | ${ipv4_address2} | ${ipv4_prefix} | | ... | @{ipv4_neighbor} | | ... | ${ipv4_settings} -| | And IPv4 config from VAT should be +| | Run Keyword And Continue On Failure +| | ... | And IPv4 config from VAT should be | | ... | ${node} | ${interface} | ${ipv4_address2} | ${ipv4_prefix} | Honeycomb modifies interface configuration - ipv6 @@ -99,10 +109,12 @@ | | When Honeycomb sets interface ipv6 configuration | | ... | ${node} | ${interface} | @{ipv6_address} | @{ipv6_neighbor} | | ... | ${ipv6_settings} -| | Then IPv6 config from Honeycomb should be +| | Run Keyword And Continue On Failure +| | ... | Then IPv6 config from Honeycomb should be | | ... | ${node} | ${interface} | @{ipv6_address} | @{ipv6_neighbor} | | ... | ${ipv6_settings} -| | And IPv6 config from VAT should be +| | Run Keyword And Continue On Failure +| | ... | And IPv6 config from VAT should be | | ... | ${node} | ${interface} | @{ipv6_address} | Honeycomb modifies interface configuration - ethernet,routing diff --git a/tests/func/honeycomb/020_bridge_domain.robot b/tests/func/honeycomb/020_bridge_domain.robot index d4293dcdf7..bd182e34a9 100644 --- a/tests/func/honeycomb/020_bridge_domain.robot +++ b/tests/func/honeycomb/020_bridge_domain.robot @@ -25,9 +25,13 @@ *** Settings *** | Resource | resources/libraries/robot/default.robot +| Resource | resources/libraries/robot/honeycomb/honeycomb.robot | Resource | resources/libraries/robot/honeycomb/interfaces.robot | Resource | resources/libraries/robot/honeycomb/bridge_domain.robot -| Suite Teardown | Honeycomb removes all bridge domains | ${node} +| Suite Teardown | Run keywords +| ... | Run Keyword If Any Tests Failed +| ... | Restart Honeycomb And VPP And Clear Persisted Configuration | ${node} +| ... | AND | Honeycomb removes all bridge domains | ${node} | Force Tags | honeycomb_sanity | Documentation | *Honeycomb bridge domain management test suite.* | ... diff --git a/tests/func/honeycomb/021_l2_fib.robot b/tests/func/honeycomb/021_l2_fib.robot index ec07e104ad..b7e0f8dc02 100644 --- a/tests/func/honeycomb/021_l2_fib.robot +++ b/tests/func/honeycomb/021_l2_fib.robot @@ -13,21 +13,27 @@ *** Settings *** | Resource | resources/libraries/robot/default.robot +| Resource | resources/libraries/robot/honeycomb/honeycomb.robot | Resource | resources/libraries/robot/honeycomb/interfaces.robot | Resource | resources/libraries/robot/honeycomb/bridge_domain.robot | Resource | resources/libraries/robot/honeycomb/l2_fib.robot -| Variables | resources/test_data/honeycomb/l2_fib.py +| Variables | resources/test_data/honeycomb/l2_fib.py | ${node} | ${interface} +| ... | ${interface2} | Documentation | *Honeycomb L2 FIB management test suite.* | Suite Setup | Run keywords | ... | Set test interface down | ... | AND | ... | Honeycomb removes all bridge domains | ${node} -| Suite Teardown | Honeycomb removes all bridge domains | ${node} +| Suite Teardown | Run keywords +| ... | Run Keyword If Any Tests Failed +| ... | Restart Honeycomb And VPP And Clear Persisted Configuration | ${node} +| ... | AND | Honeycomb removes all bridge domains | ${node} | Force tags | honeycomb_sanity *** Variables *** # Interface to run tests on. | ${interface}= | ${node['interfaces']['port1']['name']} +| ${interface2}= | ${node['interfaces']['port3']['name']} *** Test Cases *** | Honeycomb adds L2 FIB entry (forward) diff --git a/tests/func/honeycomb/030_vxlan.robot b/tests/func/honeycomb/030_vxlan.robot index 7e192cea47..7aa77f3ae8 100644 --- a/tests/func/honeycomb/030_vxlan.robot +++ b/tests/func/honeycomb/030_vxlan.robot @@ -27,11 +27,14 @@ *** Settings *** | Resource | resources/libraries/robot/default.robot +| Resource | resources/libraries/robot/honeycomb/honeycomb.robot | Resource | resources/libraries/robot/honeycomb/interfaces.robot | Resource | resources/libraries/robot/honeycomb/vxlan.robot # import additional VxLAN settings from resource file | Variables | resources/test_data/honeycomb/vxlan.py | Force Tags | honeycomb_sanity +| Suite Teardown | Run Keyword If Any Tests Failed +| ... | Restart Honeycomb And VPP And Clear Persisted Configuration | ${node} | Documentation | *Honeycomb VxLAN management test suite.* | ... | ... | Test suite uses the first interface of the first DUT node. diff --git a/tests/func/honeycomb/031_vxlan_gpe.robot b/tests/func/honeycomb/031_vxlan_gpe.robot index 5c51319070..54347e5725 100644 --- a/tests/func/honeycomb/031_vxlan_gpe.robot +++ b/tests/func/honeycomb/031_vxlan_gpe.robot @@ -33,16 +33,20 @@ *** Settings *** | Resource | resources/libraries/robot/default.robot +| Resource | resources/libraries/robot/honeycomb/honeycomb.robot | Resource | resources/libraries/robot/honeycomb/interfaces.robot | Resource | resources/libraries/robot/honeycomb/vxlan_gpe.robot # Import additional VxLAN GPE settings from resource file | Variables | resources/test_data/honeycomb/vxlan_gpe.py | Documentation | *Honeycomb VxLAN-GPE management test suite.* | Force Tags | honeycomb_sanity +| Suite Teardown | Run Keyword If Any Tests Failed +| ... | Restart Honeycomb And VPP And Clear Persisted Configuration | ${node} *** Test Cases *** +# TODO: Remove "continue on failure" once VPP bugs (VPP-217, VPP-156) are fixed. | Honeycomb creates VxLAN GPE tunnel -| | [Documentation] | Check if Honeycomb API can configure VxLAN GPE tunnel. +| | [Documentation] | Check if Honeycomb API can configure a VxLAN GPE tunnel. | | ... | | Given interface configuration from Honeycomb should be empty | | ... | ${node} | ${vxlan_gpe_if1} @@ -51,34 +55,31 @@ | | When Honeycomb creates VxLAN GPE interface | | ... | ${node} | ${vxlan_gpe_if1} | | ... | ${vxlan_gpe_base_settings} | ${vxlan_gpe_settings} -| | Then run keyword and continue on failure -| | ... | VxLAN GPE configuration from Honeycomb should be +| | Then VxLAN GPE configuration from Honeycomb should be | | ... | ${node} | ${vxlan_gpe_if1} | | ... | ${vxlan_gpe_base_settings} | ${vxlan_gpe_settings} | | And run keyword and continue on failure | | ... | VxLAN GPE configuration from VAT should be | | ... | ${node} | ${vxlan_gpe_if1} | ${vxlan_gpe_settings} -| | And run keyword and continue on failure -| | ... | VxLAN GPE Interface indices from Honeycomb and VAT should correspond +| | And VxLAN GPE Interface indices from Honeycomb and VAT should correspond | | ... | ${node} | ${vxlan_gpe_if1} | Honeycomb removes VxLAN GPE tunnel | | [Documentation] | Check if Honeycomb API can remove VxLAN GPE tunnel. | | ... -# Disabled beacuse of bug in Honeycomb. -# TODO: Enable when fixed. -#| | Given VxLAN GPE configuration from Honeycomb should be -#| | ... | ${node} | ${vxlan_gpe_if1} -#| | ... | ${vxlan_gpe_base_settings} | ${vxlan_gpe_settings} -#| | And VxLAN GPE configuration from VAT should be -#| | ... | ${node} | ${vxlan_gpe_if1} | ${vxlan_gpe_settings} +| | Run Keyword And Continue On Failure +| | ... | Given VxLAN GPE configuration from Honeycomb should be +| | ... | ${node} | ${vxlan_gpe_if1} +| | ... | ${vxlan_gpe_base_settings} | ${vxlan_gpe_settings} +| | Run Keyword And Continue On Failure +| | ... | And VxLAN GPE configuration from VAT should be +| | ... | ${node} | ${vxlan_gpe_if1} | ${vxlan_gpe_settings} | | When Honeycomb removes VxLAN GPE interface | | ... | ${node} | ${vxlan_gpe_if1} -| | Then VxLAN GPE configuration from VAT should be empty -| | ... | ${node} -| | And VxLAN GPE configuration from Honeycomb should be +| | Then VxLAN GPE configuration from Honeycomb should be empty | | ... | ${node} | ${vxlan_gpe_if1} -| | ... | ${vxlan_gpe_disabled_base_settings} | ${vxlan_gpe_settings} +| | And VxLAN GPE configuration from VAT should be empty +| | ... | ${node} | Honeycomb sets wrong interface type while creating VxLAN GPE tunnel | | [Documentation] | Check if Honeycomb refuses to create a VxLAN GPE tunnel\ @@ -127,32 +128,27 @@ | | ... | ${node} | Honeycomb creates VxLAN GPE tunnel with ipv6 -| | [Documentation] | Check if Honeycomb API can configure VxLAN GPE tunnel\ +| | [Documentation] | Check if Honeycomb API can configure a VxLAN GPE tunnel\ | | ... | with IPv6 addresses. | | ... | | Given VxLAN GPE configuration from VAT should be empty | | ... | ${node} -# Disabled beacuse of bug in Honeycomb -# TODO: Enable when fixed. -#| | And VxLAN GPE configuration from Honeycomb should be -#| | ... | ${node} | ${vxlan_gpe_if5} -#| | ... | ${vxlan_gpe_disabled_base_settings} | ${vxlan_gpe_settings} +| | And VxLAN GPE configuration from Honeycomb should be empty +| | ... | ${node} | ${vxlan_gpe_if5} | | When Honeycomb creates VxLAN GPE interface | | ... | ${node} | ${vxlan_gpe_if5} | | ... | ${vxlan_gpe_base_ipv6_settings} | ${vxlan_gpe_ipv6_settings} -| | Then run keyword and continue on failure -| | ... | VxLAN GPE configuration from Honeycomb should be +| | Then VxLAN GPE configuration from Honeycomb should be | | ... | ${node} | ${vxlan_gpe_if5} | | ... | ${vxlan_gpe_base_ipv6_settings} | ${vxlan_gpe_ipv6_settings} -| | And run keyword and continue on failure +| | And Run Keyword And Continue On Failure | | ... | VxLAN GPE configuration from VAT should be | | ... | ${node} | ${vxlan_gpe_if5} | ${vxlan_gpe_ipv6_settings} -| | And run keyword and continue on failure -| | ... | VxLAN GPE Interface indices from Honeycomb and VAT should correspond +| | And VxLAN GPE Interface indices from Honeycomb and VAT should correspond | | ... | ${node} | ${vxlan_gpe_if5} -| Honeycomb creates the second VxLAN GPE tunnel with ipv6 -| | [Documentation] | Check if Honeycomb API can configure another one VxLAN\ +| Honeycomb creates a second VxLAN GPE tunnel with ipv6 +| | [Documentation] | Check if Honeycomb API can configure another VxLAN\ | | ... | GPE tunnel with IPv6 addresses. | | ... | | Given interface configuration from Honeycomb should be empty @@ -162,13 +158,11 @@ | | When Honeycomb creates VxLAN GPE interface | | ... | ${node} | ${vxlan_gpe_if6} | | ... | ${vxlan_gpe_base_ipv6_settings2} | ${vxlan_gpe_ipv6_settings2} -| | Then run keyword and continue on failure -| | ... | VxLAN GPE configuration from Honeycomb should be +| | Then VxLAN GPE configuration from Honeycomb should be | | ... | ${node} | ${vxlan_gpe_if6} | | ... | ${vxlan_gpe_base_ipv6_settings2} | ${vxlan_gpe_ipv6_settings2} | | And run keyword and continue on failure | | ... | VxLAN GPE configuration from VAT should be | | ... | ${node} | ${vxlan_gpe_if6} | ${vxlan_gpe_ipv6_settings2} -| | And run keyword and continue on failure -| | ... | VxLAN GPE Interface indices from Honeycomb and VAT should correspond +| | And VxLAN GPE Interface indices from Honeycomb and VAT should correspond | | ... | ${node} | ${vxlan_gpe_if6} diff --git a/tests/func/honeycomb/040_tap.robot b/tests/func/honeycomb/040_tap.robot index 329ca8a3c1..cf45107ade 100644 --- a/tests/func/honeycomb/040_tap.robot +++ b/tests/func/honeycomb/040_tap.robot @@ -23,9 +23,12 @@ *** Settings *** | Resource | resources/libraries/robot/default.robot +| Resource | resources/libraries/robot/honeycomb/honeycomb.robot | Resource | resources/libraries/robot/honeycomb/interfaces.robot | Resource | resources/libraries/robot/honeycomb/tap.robot | Force Tags | honeycomb_sanity +| Suite Teardown | Run Keyword If Any Tests Failed +| ... | Restart Honeycomb And VPP And Clear Persisted Configuration | ${node} | Documentation | *Honeycomb TAP management test suite.* | ... | ... | Test suite uses the first interface of the first DUT node. diff --git a/tests/func/honeycomb/050_interface_vhost_user.robot b/tests/func/honeycomb/050_interface_vhost_user.robot index 2c2a5ae91a..afc70715ee 100644 --- a/tests/func/honeycomb/050_interface_vhost_user.robot +++ b/tests/func/honeycomb/050_interface_vhost_user.robot @@ -24,8 +24,11 @@ *** Settings *** | Resource | resources/libraries/robot/default.robot +| Resource | resources/libraries/robot/honeycomb/honeycomb.robot | Resource | resources/libraries/robot/honeycomb/vhost_user.robot | Force Tags | honeycomb_sanity +| Suite Teardown | Run Keyword If Any Tests Failed +| ... | Restart Honeycomb And VPP And Clear Persisted Configuration | ${node} | Documentation | *Honeycomb vhost-user interface management test suite.* | ... | ... | This test suite tests if it is posible to create, modify and\ diff --git a/tests/func/honeycomb/060_sub_interface.robot b/tests/func/honeycomb/060_sub_interface.robot index e67638ab97..8f12dd65dc 100644 --- a/tests/func/honeycomb/060_sub_interface.robot +++ b/tests/func/honeycomb/060_sub_interface.robot @@ -13,11 +13,15 @@ *** Settings *** | Resource | resources/libraries/robot/default.robot +| Resource | resources/libraries/robot/honeycomb/honeycomb.robot | Resource | resources/libraries/robot/honeycomb/sub_interface.robot | Resource | resources/libraries/robot/honeycomb/bridge_domain.robot | Resource | resources/libraries/robot/honeycomb/interfaces.robot | Variables | resources/test_data/honeycomb/sub_interfaces.py -| Suite Teardown | Honeycomb removes all bridge domains | ${node} +| Suite Teardown | Run keywords +| ... | Run Keyword If Any Tests Failed +| ... | Restart Honeycomb And VPP And Clear Persisted Configuration | ${node} +| ... | AND | Honeycomb removes all bridge domains | ${node} | Force Tags | honeycomb_sanity | Documentation | *Honeycomb sub-interface management test suite.* | ... @@ -34,7 +38,7 @@ | Honycomb creates sub-interface | | [Documentation] | Check if Honeycomb creates a sub-interface. | | ... -| | Given interface state is | ${node} | ${super_if} | down +| | Given Interface State Is | ${node} | ${super_if} | down | | And sub-interface configuration from Honeycomb should be empty | | ... | ${node} | ${super_if} | ${sub_if_id} | | And interface configuration from VAT should be empty @@ -347,6 +351,7 @@ | | ... | ${node} | ${sub_if_name} | | ... | ${ipv4['address']} | ${ipv4['prefix-length']} +#TODO: Remove "continue on failure" once VPP bug VPP-132 is fixed. | Honeycomb removes sub-interface ipv4 address | | [Documentation] | Check if Honeycomb can remove configured ipv4 addresses\ | | ... | from the sub-interface. @@ -354,7 +359,8 @@ | | Given sub-interface ipv4 address from Honeycomb should be | | ... | ${node} | ${super_if} | ${sub_if_id} | | ... | ${ipv4['address']} | ${ipv4['prefix-length']} -| | And sub-interface ipv4 address from VAT should be +| | Run Keyword And Continue On Failure +| | ... | And sub-interface ipv4 address from VAT should be | | ... | ${node} | ${sub_if_name} | | ... | ${ipv4['address']} | ${ipv4['prefix-length']} | | When Honeycomb removes all sub-interface ipv4 addresses diff --git a/tests/func/honeycomb/070_netconf.robot b/tests/func/honeycomb/070_netconf.robot index 9925dee15f..3f2244633f 100644 --- a/tests/func/honeycomb/070_netconf.robot +++ b/tests/func/honeycomb/070_netconf.robot @@ -13,11 +13,14 @@ *** Settings *** | Resource | resources/libraries/robot/default.robot +| Resource | resources/libraries/robot/honeycomb/honeycomb.robot | Resource | resources/libraries/robot/honeycomb/netconf.robot | Variables | resources/test_data/honeycomb/netconf/triggers.py | Documentation | *Netconf test suite. Contains test cases that need to bypass\ | ... | REST API.* | Force Tags | honeycomb_sanity +| Suite Teardown | Run Keyword If Any Tests Failed +| ... | Restart Honeycomb And VPP And Clear Persisted Configuration | ${node} *** Test Cases *** | Honeycomb can create and delete interfaces diff --git a/tests/func/honeycomb/071_notification.robot b/tests/func/honeycomb/071_notification.robot index 117f024b21..41d04913a6 100644 --- a/tests/func/honeycomb/071_notification.robot +++ b/tests/func/honeycomb/071_notification.robot @@ -20,6 +20,7 @@ *** Settings *** | Resource | resources/libraries/robot/default.robot +| Resource | resources/libraries/robot/honeycomb/honeycomb.robot | Resource | resources/libraries/robot/honeycomb/interfaces.robot | Resource | resources/libraries/robot/honeycomb/tap.robot | Resource | resources/libraries/robot/honeycomb/notifications.robot @@ -30,6 +31,8 @@ | ... | ${node} | ${tap_interface} | ${tap_settings} | Documentation | *Honeycomb notifications test suite.* | Force Tags | honeycomb_sanity +| Suite Teardown | Run Keyword If Any Tests Failed +| ... | Restart Honeycomb And VPP And Clear Persisted Configuration | ${node} *** Test Cases *** | Honeycomb sends notification on interface state change diff --git a/tests/func/honeycomb/080_access_control_lists.robot b/tests/func/honeycomb/080_access_control_lists.robot index 146a02edd3..e7a864e473 100644 --- a/tests/func/honeycomb/080_access_control_lists.robot +++ b/tests/func/honeycomb/080_access_control_lists.robot @@ -11,15 +11,19 @@ # See the License for the specific language governing permissions and # limitations under the License. -*** Variables*** +*** Variables *** # Interface to run tests on. | ${interface}= | ${node['interfaces']['port1']['name']} *** Settings *** | Resource | resources/libraries/robot/default.robot +| Resource | resources/libraries/robot/honeycomb/honeycomb.robot | Resource | resources/libraries/robot/honeycomb/access_control_lists.robot | Variables | resources/test_data/honeycomb/acl.py -| Suite Teardown | Clear all ACL settings | ${node} +| Suite Teardown | Run keywords +| ... | Run Keyword If Any Tests Failed +| ... | Restart Honeycomb And VPP And Clear Persisted Configuration | ${node} +| ... | AND | Clear all ACL settings | ${node} | Documentation | *Honeycomb access control lists test suite.* | Force Tags | Honeycomb_sanity diff --git a/tests/func/honeycomb/900_persistence.robot b/tests/func/honeycomb/900_persistence.robot index e3f68ccc33..ffbc94e635 100644 --- a/tests/func/honeycomb/900_persistence.robot +++ b/tests/func/honeycomb/900_persistence.robot @@ -18,9 +18,9 @@ *** Settings *** | Resource | resources/libraries/robot/default.robot | Resource | resources/libraries/robot/honeycomb/persistence.robot -| Suite Setup | Restart Honeycomb and VPP and clear persisted configuration +| Suite Setup | Restart Honeycomb And VPP And Clear Persisted Configuration | ... | ${node} -| Force Tags | honeycomb_persistence +| Force Tags | honeycomb_sanity | Documentation | *Honeycomb configuration persistence test suite.* *** Test Cases *** @@ -53,24 +53,7 @@ | | [Documentation] | Checks if Honeycomb reverts to default configuration when\ | | ... | persistence files are damaged or invalid. | | [Teardown] | Run keyword if test failed -| | ... | Restart both systems and clear persisted configuration | ${node} +| | ... | Restart Honeycomb And VPP And Clear Persisted Configuration | ${node} | | Given Honeycomb and VPP should not have default configuration | ${node} | | When Persistence file is damaged during restart | ${node} | | Then Honeycomb and VPP should have default configuration | ${node} - -*** Keywords *** -| Restart Honeycomb and VPP and clear persisted configuration -| | [Documentation] | Restarts Honeycomb and VPP with default configuration. -| | ... -| | ... | *Arguments:* -| | ... | - node - information about a DUT node. Type: dictionary -| | ... -| | ... | *Example:* -| | ... -| | ... | Restart both systems and clear persisted configuration \ -| | ... | \| ${nodes['DUT1']} \| -| | [Arguments] | ${node} -| | Stop Honeycomb service on DUTs | ${node} -| | Clear persisted Honeycomb configuration | ${node} -| | Setup DUT | ${node} -| | Setup Honeycomb service on DUTs | ${node} \ No newline at end of file diff --git a/tests/func/honeycomb/__init__.robot b/tests/func/honeycomb/__init__.robot index d38852a090..a38d53a464 100644 --- a/tests/func/honeycomb/__init__.robot +++ b/tests/func/honeycomb/__init__.robot @@ -16,11 +16,12 @@ | ${node}= | ${nodes['DUT1']} *** Settings *** -| Library | resources.libraries.python.honeycomb.HcPersistence +| Library | resources/libraries/python/honeycomb/HcPersistence.py | Resource | resources/libraries/robot/default.robot | Resource | resources/libraries/robot/honeycomb/honeycomb.robot -| Suite Setup | Run keywords | Setup all DUTs before test | AND -| ... | Clear persisted Honeycomb configuration | ${node} | AND -| ... | Setup Honeycomb service on DUTs | ${node} | AND +| Suite Setup | Run Keywords | Setup All DUTs Before Test | AND +| ... | Clear Persisted Honeycomb Configuration | ${node} | AND +| ... | Configure Unsecured Access | ${node} | AND +| ... | Setup Honeycomb Service On DUTs | ${node} | AND | ... | Set Global Variable | ${node} -| Suite Teardown | Stop Honeycomb service on DUTs | ${node} +| Suite Teardown | Stop Honeycomb Service On DUTs | ${node}