diff --git a/staticlibs/tests/unit/host/python/apf_utils_test.py b/staticlibs/tests/unit/host/python/apf_utils_test.py index d4753b7633..55fbe58c7a 100644 --- a/staticlibs/tests/unit/host/python/apf_utils_test.py +++ b/staticlibs/tests/unit/host/python/apf_utils_test.py @@ -27,6 +27,7 @@ from net_tests_utils.host.python.apf_utils import ( get_apf_counters_from_dumpsys, get_ipv4_addresses, get_non_tentative_ipv6_addresses, + get_exclude_all_host_ipv6_multicast_addresses, get_hardware_address, is_send_raw_packet_downstream_supported, is_packet_capture_supported, @@ -170,6 +171,31 @@ IpClient.wlan1 ip_addresses = get_non_tentative_ipv6_addresses(self.mock_ad, "wlan0") asserts.assert_equal(ip_addresses, []) + + @patch("net_tests_utils.host.python.adb_utils.adb_shell") + def test_get_exclude_all_host_ipv6_multicast_addresses_success( + self, mock_adb_shell: MagicMock + ) -> None: + mock_adb_shell.return_value = """ +47: wlan0 + inet6 ff02::1:ff99:37b0 + inet6 ff02::1:ffb7:cba2 users 2 + inet6 ff02::1 + inet6 ff01::1 +""" + ip_addresses = get_exclude_all_host_ipv6_multicast_addresses(self.mock_ad, "wlan0") + asserts.assert_equal(ip_addresses, + ["ff02::1:ff99:37b0", + "ff02::1:ffb7:cba2"]) + + @patch("net_tests_utils.host.python.adb_utils.adb_shell") + def test_get_exclude_all_host_ipv6_multicast_addresses_not_found( + self, mock_adb_shell: MagicMock + ) -> None: + mock_adb_shell.return_value = "" + ip_addresses = get_exclude_all_host_ipv6_multicast_addresses(self.mock_ad, "wlan0") + asserts.assert_equal(ip_addresses, []) + @patch("net_tests_utils.host.python.adb_utils.adb_shell") def test_send_raw_packet_downstream_success( self, mock_adb_shell: MagicMock diff --git a/staticlibs/testutils/host/python/apf_utils.py b/staticlibs/testutils/host/python/apf_utils.py index 1648d36002..3c97d446d8 100644 --- a/staticlibs/testutils/host/python/apf_utils.py +++ b/staticlibs/testutils/host/python/apf_utils.py @@ -148,6 +148,38 @@ def get_non_tentative_ipv6_addresses( else: return [] +def get_exclude_all_host_ipv6_multicast_addresses( + ad: android_device.AndroidDevice, iface_name: str +) -> list[str]: + """Retrieves the IPv6 multicast addresses of a given interface on an Android device. + + This function executes an ADB shell command (`ip -6 maddr show`) to get the + network interface information and extracts the IPv6 multicast address from the output. + If devices have no IPv6 multicast address, raise PatternNotFoundException. + + Args: + ad: The Android device object. + iface_name: The name of the network interface (e.g., "wlan0"). + + Returns: + The IPv6 multicast addresses of the interface as a list of string. + Return empty list if no IPv6 multicast address. + """ + # output format + # 47: wlan0 + # inet6 ff02::1:ff99:37b0 + # inet6 ff02::1:ffb7:cba2 users 2 + # inet6 ff02::1 + # inet6 ff01::1 + output = adb_utils.adb_shell(ad, f"ip -6 maddr show {iface_name}") + pattern = r"inet6\s+([a-fA-F0-9:]+)(?:\s+users\s+\d+)?" + matches = re.findall(pattern, output) + + if matches: + return [addr for addr in matches if addr not in ("ff02::1", "ff01::1")] + else: + return [] + def get_hardware_address( ad: android_device.AndroidDevice, iface_name: str ) -> str: