diff --git a/cmd/prepare b/cmd/prepare index 252d505a0..9e68f734d 100755 --- a/cmd/prepare +++ b/cmd/prepare @@ -20,6 +20,6 @@ echo Installing system dependencies # Install system dependencies -sudo apt-get update && sudo apt-get install openvswitch-common openvswitch-switch python3 libpangocairo-1.0-0 +sudo apt-get update && sudo apt-get install openvswitch-common openvswitch-switch python3 libpangocairo-1.0-0 ethtool echo Finished installing system dependencies diff --git a/framework/python/src/net_orc/ip_control.py b/framework/python/src/net_orc/ip_control.py index 1eeafc1a9..506b23a95 100644 --- a/framework/python/src/net_orc/ip_control.py +++ b/framework/python/src/net_orc/ip_control.py @@ -42,7 +42,7 @@ def add_namespace(self, namespace): return success def check_interface_status(self, interface_name): - output = util.run_command(cmd=f'ip link show {interface_name}',output=True) + output = util.run_command(cmd=f'ip link show {interface_name}', output=True) if 'state DOWN ' in output[0]: return False else: @@ -81,6 +81,22 @@ def get_links(self): netns_links.append(interface_name.strip()) return netns_links + def get_iface_connection_stats(self, iface): + """Extract information about the physical connection""" + response = util.run_command(f'ethtool {iface}') + if len(response[1]) == 0: + return response[0] + else: + return None + + def get_iface_port_stats(self, iface): + """Extract information about packets connection""" + response = util.run_command(f'ethtool -S {iface}') + if len(response[1]) == 0: + return response[0] + else: + return None + def get_namespaces(self): result = util.run_command('ip netns list') #Strip ID's from the namespace results diff --git a/framework/python/src/net_orc/network_orchestrator.py b/framework/python/src/net_orc/network_orchestrator.py index aa23f1918..11c5918a9 100644 --- a/framework/python/src/net_orc/network_orchestrator.py +++ b/framework/python/src/net_orc/network_orchestrator.py @@ -173,6 +173,7 @@ def _device_discovered(self, mac_addr): # Ignore discovered device return + self._get_port_stats(pre_monitor=True) self._monitor_in_progress = True LOGGER.debug( @@ -203,6 +204,8 @@ def _device_discovered(self, mac_addr): with open(runtime_device_conf, 'w', encoding='utf-8') as f: json.dump(self._session.get_target_device().to_config_json(), f, indent=2) + self._get_conn_stats() + if device.ip_addr is None: LOGGER.info( f'Timed out whilst waiting for {mac_addr} to obtain an IP address') @@ -216,6 +219,31 @@ def _device_discovered(self, mac_addr): self._start_device_monitor(device) + def _get_conn_stats(self): + """ Extract information about the physical connection + and store it to a file for the conn test module to access""" + dev_int = self._session.get_device_interface() + conn_stats = self._ip_ctrl.get_iface_connection_stats(dev_int) + if conn_stats is not None: + eth_out_file = os.path.join(NET_DIR, 'ethtool_conn_stats.txt') + with open(eth_out_file, 'w', encoding='utf-8') as f: + f.write(conn_stats) + else: + LOGGER.error('Failed to generate connection stats') + + def _get_port_stats(self, pre_monitor=True): + """ Extract information about the port statistics + and store it to a file for the conn test module to access""" + dev_int = self._session.get_device_interface() + port_stats = self._ip_ctrl.get_iface_port_stats(dev_int) + if port_stats is not None: + suffix = 'pre_monitor' if pre_monitor else 'post_monitor' + eth_out_file = os.path.join(NET_DIR, f'ethtool_port_stats_{suffix}.txt') + with open(eth_out_file, 'w', encoding='utf-8') as f: + f.write(port_stats) + else: + LOGGER.error('Failed to generate port stats') + def monitor_in_progress(self): return self._monitor_in_progress @@ -261,6 +289,7 @@ def _start_device_monitor(self, device): wrpcap(os.path.join(device_runtime_dir, 'monitor.pcap'), self._monitor_packets) self._monitor_in_progress = False + self._get_port_stats(pre_monitor=False) self.get_listener().call_callback(NetworkEvent.DEVICE_STABLE, device.mac_addr) @@ -498,23 +527,22 @@ def _start_network_service(self, net_module): try: client = docker.from_env() net_module.container = client.containers.run( - net_module.image_name, - auto_remove=True, - cap_add=['NET_ADMIN'], - name=net_module.container_name, - hostname=net_module.container_name, - # Undetermined version of docker seems to have broken - # DNS configuration (/etc/resolv.conf) Re-add when/if - # this network is utilized and DNS issue is resolved - #network=PRIVATE_DOCKER_NET, - privileged=True, - detach=True, - mounts=net_module.mounts, - environment={ - 'TZ': self.get_session().get_timezone(), - 'HOST_USER': util.get_host_user() - } - ) + net_module.image_name, + auto_remove=True, + cap_add=['NET_ADMIN'], + name=net_module.container_name, + hostname=net_module.container_name, + # Undetermined version of docker seems to have broken + # DNS configuration (/etc/resolv.conf) Re-add when/if + # this network is utilized and DNS issue is resolved + #network=PRIVATE_DOCKER_NET, + privileged=True, + detach=True, + mounts=net_module.mounts, + environment={ + 'TZ': self.get_session().get_timezone(), + 'HOST_USER': util.get_host_user() + }) except docker.errors.ContainerError as error: LOGGER.error('Container run error') LOGGER.error(error) diff --git a/modules/test/conn/README.md b/modules/test/conn/README.md index cf79c3efb..c2f6377c6 100644 --- a/modules/test/conn/README.md +++ b/modules/test/conn/README.md @@ -14,6 +14,9 @@ Within the ```python/src``` directory, the below tests are executed. A few dhcp | ID | Description | Expected Behavior | Required Result | |------------------------------|----------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------| +| connection.port_link | The network switch port connected to the device has an active link without errors | When the etherent cable is connected to the port, the device triggers the port to its enabled \"Link UP\" (LEDs illuminate on device and switch ports if present) state, and the switch shows no errors with the LEDs and when interrogated with a \"show interface\" command on most network switches. | Required | +| connection.port_speed | The network switch port connected to the device has auto-negotiated a speed that is 10 Mbps or higher | When the ethernet cable is connected to the port, the device autonegotiates a speed that can be checked with the \"show interface\" command on most network switches. The output of this command must also show that the \"configured speed\" is set to \"auto\". | Required | +| connection.port_duplex | The network switch port connected to the device has auto-negotiated full-duplex. | When the ethernet cable is connected to the port, the device autonegotiates a full-duplex connection. | Required | | connection.dhcp_address | The device under test has received an IP address from the DHCP server and responds to an ICMP echo (ping) request | The device is not set up with a static IP address. The device accepts an IP address from a DHCP server (RFC 2131) and responds successfully to an ICMP echo (ping) request. | Required | | connection.mac_address | Check and note device physical address. | N/A | Required | | connection.mac_oui | The device under test has a MAC address prefix that is registered against a known manufacturer. | The MAC address prefix is registered in the IEEE Organizationally Unique Identifier database. | Required | diff --git a/modules/test/conn/conf/module_config.json b/modules/test/conn/conf/module_config.json index 888a06c48..5289e7eb0 100644 --- a/modules/test/conn/conf/module_config.json +++ b/modules/test/conn/conf/module_config.json @@ -13,6 +13,24 @@ "timeout": 1800 }, "tests": [ + { + "name": "connection.port_link", + "test_description": "The network switch port connected to the device has an active link without errors", + "expected_behavior": "When the etherent cable is connected to the port, the device triggers the port to its enabled \"Link UP\" (LEDs illuminate on device and switch ports if present) state, and the switch shows no errors with the LEDs and when interrogated with a \"show interface\" command on most network switches.", + "required_result": "Required" + }, + { + "name": "connection.port_speed", + "test_description": "The network switch port connected to the device has auto-negotiated a speed that is 10 Mbps or higher", + "expected_behavior": "When the ethernet cable is connected to the port, the device autonegotiates a speed that can be checked with the \"show interface\" command on most network switches. The output of this command must also show that the \"configured speed\" is set to \"auto\".", + "required_result": "Required" + }, + { + "name": "connection.port_duplex", + "test_description": "The network switch port connected to the device has auto-negotiated full-duplex", + "expected_behavior": "When the ethernet cable is connected to the port, the device autonegotiates a full-duplex connection.", + "required_result": "Required" + }, { "name": "connection.switch.arp_inspection", "test_description": "The device implements ARP correctly as per RFC826", diff --git a/modules/test/conn/python/src/connection_module.py b/modules/test/conn/python/src/connection_module.py index 34e129103..7df9aa3d9 100644 --- a/modules/test/conn/python/src/connection_module.py +++ b/modules/test/conn/python/src/connection_module.py @@ -20,15 +20,16 @@ from dhcp1.client import Client as DHCPClient1 from dhcp2.client import Client as DHCPClient2 from dhcp_util import DHCPUtil +from port_stats_util import PortStatsUtil LOG_NAME = 'test_connection' -LOGGER = None OUI_FILE = '/usr/local/etc/oui.txt' STARTUP_CAPTURE_FILE = '/runtime/device/startup.pcap' MONITOR_CAPTURE_FILE = '/runtime/device/monitor.pcap' DHCP_CAPTURE_FILE = '/runtime/network/dhcp-1.pcap' SLAAC_PREFIX = 'fd10:77be:4186' TR_CONTAINER_MAC_PREFIX = '9a:02:57:1e:8f:' +LOGGER = None # Should be at least twice as much as the max lease time # set in the DHCP server @@ -38,10 +39,15 @@ class ConnectionModule(TestModule): """Connection Test module""" - def __init__(self, module): - super().__init__(module_name=module, log_name=LOG_NAME) + def __init__(self, module, log_dir=None, conf_file=None, results_dir=None): + super().__init__(module_name=module, + log_name=LOG_NAME, + log_dir=log_dir, + conf_file=conf_file, + results_dir=results_dir) global LOGGER LOGGER = self._get_logger() + self._port_stats = PortStatsUtil(logger=LOGGER) self.dhcp1_client = DHCPClient1() self.dhcp2_client = DHCPClient2() self._dhcp_util = DHCPUtil(self.dhcp1_client, self.dhcp2_client, LOGGER) @@ -74,6 +80,18 @@ def __init__(self, module): # response = self.dhcp1_client.set_dhcp_range('10.10.10.20','10.10.10.30') # print("Set Range: " + str(response)) + def _connection_port_link(self): + LOGGER.info('Running connection.port_link') + return self._port_stats.connection_port_link_test() + + def _connection_port_speed(self): + LOGGER.info('Running connection.port_speed') + return self._port_stats.connection_port_speed_test() + + def _connection_port_duplex(self): + LOGGER.info('Running connection.port_duplex') + return self._port_stats.connection_port_duplex_test() + def _connection_switch_arp_inspection(self): LOGGER.info('Running connection.switch.arp_inspection') diff --git a/modules/test/conn/python/src/port_stats_util.py b/modules/test/conn/python/src/port_stats_util.py new file mode 100644 index 000000000..d923501eb --- /dev/null +++ b/modules/test/conn/python/src/port_stats_util.py @@ -0,0 +1,141 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Module that contains various methods for validating the Port statistics """ + +import os + +ETHTOOL_CONN_STATS_FILE = 'runtime/network/ethtool_conn_stats.txt' +ETHTOOL_PORT_STATS_PRE_FILE = ( + 'runtime/network/ethtool_port_stats_pre_monitor.txt') +ETHTOOL_PORT_STATS_POST_FILE = ( + 'runtime/network/ethtool_port_stats_post_monitor.txt') + +LOG_NAME = 'port_stats_util' +LOGGER = None + + +class PortStatsUtil(): + """Helper class for various tests concerning Port behavior""" + + def __init__(self, + logger, + ethtool_conn_stats_file=ETHTOOL_CONN_STATS_FILE, + ethtool_port_stats_pre_file=ETHTOOL_PORT_STATS_PRE_FILE, + ethtool_port_stats_post_file=ETHTOOL_PORT_STATS_POST_FILE): + self.ethtool_conn_stats_file = ethtool_conn_stats_file + self.ethtool_port_stats_pre_file = ethtool_port_stats_pre_file + self.ethtool_port_stats_post_file = ethtool_port_stats_post_file + global LOGGER + LOGGER = logger + self.conn_stats = self._read_stats_file(self.ethtool_conn_stats_file) + + def is_autonegotiate(self): + auto_negotiation = False + auto_negotiation_status = self._get_stat_option(stats=self.conn_stats, + option='Auto-negotiation:') + if auto_negotiation_status is not None: + auto_negotiation = 'on' in auto_negotiation_status + return auto_negotiation + + def connection_port_link_test(self): + stats_pre = self._read_stats_file(self.ethtool_port_stats_pre_file) + stats_post = self._read_stats_file(self.ethtool_port_stats_post_file) + result = None + description = '' + details = '' + if stats_pre is None or stats_pre is None: + result = 'Error' + description = 'Port stats not available' + else: + tx_errors_pre = self._get_stat_option(stats=stats_pre, + option='tx_errors:') + tx_errors_post = self._get_stat_option(stats=stats_post, + option='tx_errors:') + rx_errors_pre = self._get_stat_option(stats=stats_pre, + option='rx_errors:') + rx_errors_post = self._get_stat_option(stats=stats_post, + option='rx_errors:') + tx_errors = int(tx_errors_post) - int(tx_errors_pre) + rx_errors = int(rx_errors_post) - int(rx_errors_pre) + if tx_errors > 0 or rx_errors > 0: + result = False + description = 'Port errors detected' + details = f'TX errors: {tx_errors}, RX errors: {rx_errors}' + else: + result = True + description = 'No port errors detected' + return result, description, details + + def connection_port_duplex_test(self): + auto_negotiation = self.is_autonegotiate() + # Calculate final results + result = None + description = '' + details = '' + if not auto_negotiation: + result = False + description = 'Interface not configured for auto-negotiation' + else: + duplex = self._get_stat_option(stats=self.conn_stats, option='Duplex:') + if 'Full' in duplex: + result = True + description = 'Succesfully auto-negotiated full duplex' + details = f'Duplex negotiated: {duplex}' + else: + result = False + description = 'Failed to auto-negotate full duplex' + details = f'Duplex negotiated: {duplex}' + return result, description, details + + def connection_port_speed_test(self): + auto_negotiation = self.is_autonegotiate() + # Calculate final results + result = None + description = '' + details = '' + if not auto_negotiation: + result = False + description = 'Interface not configured for auto-negotiation' + else: + speed = self._get_stat_option(stats=self.conn_stats, option='Speed:') + if speed in ('100Mb/s', '1000Mb/s'): + result = True + description = 'Succesfully auto-negotiated speeds above 10 Mbps' + details = f'Speed negotiated: {speed}' + else: + result = False + description = 'Failed to auto-negotate speeds above 10 Mbps' + details = f'Speed negotiated: {speed}' + return result, description, details + + def _get_stat_option(self, stats, option): + """Extract the requested parameter from the ethtool result""" + value = None + for line in stats.split('\n'): + #LOGGER.info(f'Checking option: {line}') + if line.startswith(f'{option}'): + value = line.split(':')[1].strip() + break + return value + + def _read_stats_file(self, file): + if os.path.isfile(file): + with open(file, encoding='utf-8') as f: + content = f.read() + # Cleanup the results for easier processing + lines = content.split('\n') + cleaned_lines = [line.strip() for line in lines if line.strip()] + recombined_text = '\n'.join(cleaned_lines) + return recombined_text + return None diff --git a/testing/unit/conn/conn_module_test.py b/testing/unit/conn/conn_module_test.py new file mode 100644 index 000000000..d31a8051f --- /dev/null +++ b/testing/unit/conn/conn_module_test.py @@ -0,0 +1,140 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Module run all the Connection module related unit tests""" +from port_stats_util import PortStatsUtil +import os +import unittest +from common import logger + +MODULE = 'conn' +# Define the file paths +TEST_FILES_DIR = 'testing/unit/' + MODULE +ETHTOOL_RESULTS_COMPLIANT_FILE = os.path.join(TEST_FILES_DIR, 'ethtool', + 'ethtool_results_compliant.txt') +ETHTOOL_RESULTS_NONCOMPLIANT_FILE = os.path.join( + TEST_FILES_DIR, 'ethtool', 'ethtool_results_noncompliant.txt') +ETHTOOL_RESULTS_NO_AUTO_FILE = os.path.join( + TEST_FILES_DIR, 'ethtool', 'ethtool_results_no_autononegotiation.txt') + +ETHTOOL_PORT_STATS_PRE_FILE = os.path.join( + TEST_FILES_DIR, 'ethtool', 'ethtool_port_stats_pre_monitor.txt') +ETHTOOL_PORT_STATS_POST_FILE = os.path.join( + TEST_FILES_DIR, 'ethtool', 'ethtool_port_stats_post_monitor.txt') +ETHTOOL_PORT_STATS_POST_NONCOMPLIANT_FILE = os.path.join( + TEST_FILES_DIR, 'ethtool', + 'ethtool_port_stats_post_monitor_noncompliant.txt') +LOGGER = None + + +class ConnectionModuleTest(unittest.TestCase): + """Contains and runs all the unit tests concerning Connection + module behaviors""" + + @classmethod + def setUpClass(cls): + global LOGGER + LOGGER = logger.get_logger('unit_test_' + MODULE) + + # Test the port link status + def connection_port_link_compliant_test(self): + LOGGER.info('connection_port_link_compliant_test') + p_stats = PortStatsUtil( + logger=LOGGER, + ethtool_conn_stats_file=ETHTOOL_RESULTS_COMPLIANT_FILE, + ethtool_port_stats_pre_file=ETHTOOL_PORT_STATS_PRE_FILE, + ethtool_port_stats_post_file=ETHTOOL_PORT_STATS_POST_FILE) + result = p_stats.connection_port_link_test() + LOGGER.info(result) + self.assertEqual(result[0], True) + + # Test the port duplex setting + def connection_port_duplex_compliant_test(self): + LOGGER.info('connection_port_duplex_compliant_test') + p_stats = PortStatsUtil( + logger=LOGGER, ethtool_conn_stats_file=ETHTOOL_RESULTS_COMPLIANT_FILE) + result = p_stats.connection_port_duplex_test() + LOGGER.info(result) + self.assertEqual(result[0], True) + + # Test the port speed + def connection_port_speed_compliant_test(self): + LOGGER.info('connection_port_speed_compliant_test') + p_stats = PortStatsUtil( + logger=LOGGER, ethtool_conn_stats_file=ETHTOOL_RESULTS_COMPLIANT_FILE) + result = p_stats.connection_port_speed_test() + LOGGER.info(result) + self.assertEqual(result[0], True) + + # Test the port link status non-compliant + def connection_port_link_noncompliant_test(self): + LOGGER.info('connection_port_link_noncompliant_test') + p_stats = PortStatsUtil( + logger=LOGGER, + ethtool_conn_stats_file=ETHTOOL_RESULTS_COMPLIANT_FILE, + ethtool_port_stats_pre_file=ETHTOOL_PORT_STATS_PRE_FILE, + ethtool_port_stats_post_file=ETHTOOL_PORT_STATS_POST_NONCOMPLIANT_FILE) + result = p_stats.connection_port_link_test() + LOGGER.info(result) + self.assertEqual(result[0], False) + + # Test the port duplex setting non-compliant + def connection_port_duplex_noncompliant_test(self): + LOGGER.info('connection_port_duplex_noncompliant_test') + p_stats = PortStatsUtil( + logger=LOGGER, + ethtool_conn_stats_file=ETHTOOL_RESULTS_NONCOMPLIANT_FILE) + result = p_stats.connection_port_duplex_test() + LOGGER.info(result) + self.assertEqual(result[0], False) + + # Test the port speed non-compliant + def connection_port_speed_noncompliant_test(self): + LOGGER.info('connection_port_speed_noncompliant_test') + p_stats = PortStatsUtil( + logger=LOGGER, + ethtool_conn_stats_file=ETHTOOL_RESULTS_NONCOMPLIANT_FILE) + result = p_stats.connection_port_speed_test() + LOGGER.info(result) + self.assertEqual(result[0], False) + + # Test the autonegotiation failure test + def connection_port_speed_autonegotiation_fail_test(self): + LOGGER.info('connection_port_speed_autonegotiation_fail_test') + p_stats = PortStatsUtil( + logger=LOGGER, ethtool_conn_stats_file=ETHTOOL_RESULTS_NO_AUTO_FILE) + result = p_stats.connection_port_speed_test() + LOGGER.info(result) + self.assertEqual(result[0], False) + + +if __name__ == '__main__': + suite = unittest.TestSuite() + + # Compliant port stats tests + suite.addTest(ConnectionModuleTest('connection_port_link_compliant_test')) + suite.addTest(ConnectionModuleTest('connection_port_duplex_compliant_test')) + suite.addTest(ConnectionModuleTest('connection_port_speed_compliant_test')) + + # Non-compliant port stats tests + suite.addTest(ConnectionModuleTest('connection_port_link_noncompliant_test')) + suite.addTest( + ConnectionModuleTest('connection_port_duplex_noncompliant_test')) + suite.addTest(ConnectionModuleTest('connection_port_speed_noncompliant_test')) + + # Autonegotiation off failure test + suite.addTest( + ConnectionModuleTest('connection_port_speed_autonegotiation_fail_test')) + + runner = unittest.TextTestRunner() + runner.run(suite) diff --git a/testing/unit/conn/ethtool/ethtool_port_stats_post_monitor.txt b/testing/unit/conn/ethtool/ethtool_port_stats_post_monitor.txt new file mode 100644 index 000000000..a4e93ed47 --- /dev/null +++ b/testing/unit/conn/ethtool/ethtool_port_stats_post_monitor.txt @@ -0,0 +1,14 @@ +NIC statistics: + tx_packets: 124 + rx_packets: 216 + tx_errors: 0 + rx_errors: 0 + rx_missed: 0 + align_errors: 0 + tx_single_collisions: 0 + tx_multi_collisions: 0 + rx_unicast: 23 + rx_broadcast: 83 + rx_multicast: 110 + tx_aborted: 0 + tx_underrun: 0 \ No newline at end of file diff --git a/testing/unit/conn/ethtool/ethtool_port_stats_post_monitor_noncompliant.txt b/testing/unit/conn/ethtool/ethtool_port_stats_post_monitor_noncompliant.txt new file mode 100644 index 000000000..1d4b19e54 --- /dev/null +++ b/testing/unit/conn/ethtool/ethtool_port_stats_post_monitor_noncompliant.txt @@ -0,0 +1,14 @@ +NIC statistics: + tx_packets: 124 + rx_packets: 216 + tx_errors: 5 + rx_errors: 12 + rx_missed: 0 + align_errors: 0 + tx_single_collisions: 0 + tx_multi_collisions: 0 + rx_unicast: 23 + rx_broadcast: 83 + rx_multicast: 110 + tx_aborted: 0 + tx_underrun: 0 \ No newline at end of file diff --git a/testing/unit/conn/ethtool/ethtool_port_stats_pre_monitor.txt b/testing/unit/conn/ethtool/ethtool_port_stats_pre_monitor.txt new file mode 100644 index 000000000..18e027efb --- /dev/null +++ b/testing/unit/conn/ethtool/ethtool_port_stats_pre_monitor.txt @@ -0,0 +1,14 @@ +NIC statistics: + tx_packets: 90 + rx_packets: 195 + tx_errors: 0 + rx_errors: 0 + rx_missed: 0 + align_errors: 0 + tx_single_collisions: 0 + tx_multi_collisions: 0 + rx_unicast: 12 + rx_broadcast: 78 + rx_multicast: 105 + tx_aborted: 0 + tx_underrun: 0 \ No newline at end of file diff --git a/testing/unit/conn/ethtool/ethtool_results_compliant.txt b/testing/unit/conn/ethtool/ethtool_results_compliant.txt new file mode 100644 index 000000000..911e8912f --- /dev/null +++ b/testing/unit/conn/ethtool/ethtool_results_compliant.txt @@ -0,0 +1,30 @@ +Settings for enx123456789: + Supported ports: [ TP MII ] + Supported link modes: 10baseT/Half 10baseT/Full + 100baseT/Half 100baseT/Full + 1000baseT/Half 1000baseT/Full + Supported pause frame use: No + Supports auto-negotiation: Yes + Supported FEC modes: Not reported + Advertised link modes: 10baseT/Half 10baseT/Full + 100baseT/Half 100baseT/Full + 1000baseT/Full + Advertised pause frame use: Symmetric Receive-only + Advertised auto-negotiation: Yes + Advertised FEC modes: Not reported + Link partner advertised link modes: 10baseT/Full + 100baseT/Half 100baseT/Full + Link partner advertised pause frame use: Symmetric + Link partner advertised auto-negotiation: Yes + Link partner advertised FEC modes: Not reported + Speed: 100Mb/s + Duplex: Full + Port: MII + PHYAD: 32 + Transceiver: internal + Auto-negotiation: on + Supports Wake-on: pumbg + Wake-on: g + Current message level: 0x00007fff (32767) + drv probe link timer ifdown ifup rx_err tx_err tx_queued intr tx_done rx_status pktdata hw wol + Link detected: yes \ No newline at end of file diff --git a/testing/unit/conn/ethtool/ethtool_results_no_autononegotiation.txt b/testing/unit/conn/ethtool/ethtool_results_no_autononegotiation.txt new file mode 100644 index 000000000..76dd4cf5b --- /dev/null +++ b/testing/unit/conn/ethtool/ethtool_results_no_autononegotiation.txt @@ -0,0 +1,30 @@ +Settings for enx123456789: + Supported ports: [ TP MII ] + Supported link modes: 10baseT/Half 10baseT/Full + 100baseT/Half 100baseT/Full + 1000baseT/Half 1000baseT/Full + Supported pause frame use: No + Supports auto-negotiation: Yes + Supported FEC modes: Not reported + Advertised link modes: 10baseT/Half 10baseT/Full + 100baseT/Half 100baseT/Full + 1000baseT/Full + Advertised pause frame use: Symmetric Receive-only + Advertised auto-negotiation: Yes + Advertised FEC modes: Not reported + Link partner advertised link modes: 10baseT/Full + 100baseT/Half 100baseT/Full + Link partner advertised pause frame use: Symmetric + Link partner advertised auto-negotiation: Yes + Link partner advertised FEC modes: Not reported + Speed: 100Mb/s + Duplex: Full + Port: MII + PHYAD: 32 + Transceiver: internal + Auto-negotiation: off + Supports Wake-on: pumbg + Wake-on: g + Current message level: 0x00007fff (32767) + drv probe link timer ifdown ifup rx_err tx_err tx_queued intr tx_done rx_status pktdata hw wol + Link detected: yes \ No newline at end of file diff --git a/testing/unit/conn/ethtool/ethtool_results_noncompliant.txt b/testing/unit/conn/ethtool/ethtool_results_noncompliant.txt new file mode 100644 index 000000000..2ca90e7d0 --- /dev/null +++ b/testing/unit/conn/ethtool/ethtool_results_noncompliant.txt @@ -0,0 +1,30 @@ +Settings for enx123456789: + Supported ports: [ TP MII ] + Supported link modes: 10baseT/Half 10baseT/Full + 100baseT/Half 100baseT/Full + 1000baseT/Half 1000baseT/Full + Supported pause frame use: No + Supports auto-negotiation: Yes + Supported FEC modes: Not reported + Advertised link modes: 10baseT/Half 10baseT/Full + 100baseT/Half 100baseT/Full + 1000baseT/Full + Advertised pause frame use: Symmetric Receive-only + Advertised auto-negotiation: Yes + Advertised FEC modes: Not reported + Link partner advertised link modes: 10baseT/Full + 100baseT/Half 100baseT/Full + Link partner advertised pause frame use: Symmetric + Link partner advertised auto-negotiation: Yes + Link partner advertised FEC modes: Not reported + Speed: 10Mb/s + Duplex: Half + Port: MII + PHYAD: 32 + Transceiver: internal + Auto-negotiation: on + Supports Wake-on: pumbg + Wake-on: g + Current message level: 0x00007fff (32767) + drv probe link timer ifdown ifup rx_err tx_err tx_queued intr tx_done rx_status pktdata hw wol + Link detected: yes \ No newline at end of file diff --git a/testing/unit/run_tests.sh b/testing/unit/run_tests.sh index 01c2b36cf..2658636dd 100644 --- a/testing/unit/run_tests.sh +++ b/testing/unit/run_tests.sh @@ -27,6 +27,7 @@ PYTHONPATH="$PWD/framework/python/src:$PWD/framework/python/src/common" # Add the test module sources PYTHONPATH="$PYTHONPATH:$PWD/modules/test/base/python/src" +PYTHONPATH="$PYTHONPATH:$PWD/modules/test/conn/python/src" PYTHONPATH="$PYTHONPATH:$PWD/modules/test/tls/python/src" PYTHONPATH="$PYTHONPATH:$PWD/modules/test/dns/python/src" PYTHONPATH="$PYTHONPATH:$PWD/modules/test/nmap/python/src" @@ -39,6 +40,9 @@ export PYTHONPATH python3 -u $PWD/modules/network/dhcp-1/python/src/grpc_server/dhcp_config_test.py python3 -u $PWD/modules/network/dhcp-2/python/src/grpc_server/dhcp_config_test.py +# Run the Conn Module Unit Tests +python3 -u $PWD/testing/unit/conn/conn_module_test.py + # Run the TLS Module Unit Tests python3 -u $PWD/testing/unit/tls/tls_module_test.py