From 744a17443a425e3320219ff02f9dbfa78216464e Mon Sep 17 00:00:00 2001 From: Jimi Chen Date: Wed, 2 Apr 2025 03:07:56 +0000 Subject: [PATCH] Improve stability of APFv{4,6} multi-device tests This commit enhances the stability of the APFv{4,6} multi-device tests by addressing several sources of flakiness and improving the test setup and validation. Specifically, this commit: * Increased sleep time in the test setup. This ensures APF is activated before each test, preventing unexpected behavior. * Added sleep time in `ApfV4Test` to ensure APF remains enabled and is not disabled due to high throughput scenarios. * Changed the validation order to first check received packets and then APF counters. This helps to more easily identify the root cause of test failures. * Changed the Ethernet destination address from multicast to unicast in `ApfV6Test` to prevent packets from being filtered due to DTIM skip. * Removed the `test_broadcast_arp_request_offload()` test, which was flaky due to DTIM skip and is adequately covered by the `test_unicast_arp_request_offload()` test. Bug: 406570694 Flag: TEST_ONLY Test: atest CtsConnectivityMultiDevicesTestCases:ApfV4Test Test: atest CtsConnectivityMultiDevicesTestCases:ApfV6Test Test: run cts -m CtsConnectivityMultiDevicesTestCases --skip-preconditions -t ApfV4Test --shard-count 2 Test: run cts -m CtsConnectivityMultiDevicesTestCases --skip-preconditions -t ApfV6Test --shard-count 2 Change-Id: I053509459078d0bd94e16a6bf7349b948f930e6c --- .../testutils/host/python/apf_test_base.py | 24 ++++++++++++-- tests/cts/multidevices/apfv4_test.py | 4 +++ tests/cts/multidevices/apfv6_test.py | 33 +++---------------- 3 files changed, 29 insertions(+), 32 deletions(-) diff --git a/staticlibs/testutils/host/python/apf_test_base.py b/staticlibs/testutils/host/python/apf_test_base.py index 6a62e21019..9d1ea02bbe 100644 --- a/staticlibs/testutils/host/python/apf_test_base.py +++ b/staticlibs/testutils/host/python/apf_test_base.py @@ -70,8 +70,8 @@ class ApfTestBase(multi_devices_test_base.MultiDevicesTestBase): # Enable doze mode to activate APF. adb_utils.set_doze_mode(self.clientDevice, True) - # wait for APF to become active. - time.sleep(3) + # Longer wait time is required for APF to become active in CTS test suite. + time.sleep(5) def teardown_class(self): adb_utils.set_doze_mode(self.clientDevice, False) @@ -106,7 +106,15 @@ class ApfTestBase(multi_devices_test_base.MultiDevicesTestBase): try: apf_utils.start_capture_packets(self.serverDevice, self.server_iface_name) - self.send_packet_and_expect_counter_increased(send_packet, counter_name) + count_before_test = apf_utils.get_apf_counter( + self.clientDevice, + self.client_iface_name, + counter_name, + ) + + apf_utils.send_raw_packet_downstream( + self.serverDevice, self.server_iface_name, send_packet + ) assert_utils.expect_with_retry( lambda: apf_utils.get_matched_packet_counts( @@ -114,5 +122,15 @@ class ApfTestBase(multi_devices_test_base.MultiDevicesTestBase): ) == 1 ) + + assert_utils.expect_with_retry( + lambda: apf_utils.get_apf_counter( + self.clientDevice, + self.client_iface_name, + counter_name, + ) + > count_before_test + ) + finally: apf_utils.stop_capture_packets(self.serverDevice, self.server_iface_name) diff --git a/tests/cts/multidevices/apfv4_test.py b/tests/cts/multidevices/apfv4_test.py index 0fc1093f5b..2f212fcdc9 100644 --- a/tests/cts/multidevices/apfv4_test.py +++ b/tests/cts/multidevices/apfv4_test.py @@ -16,6 +16,7 @@ from absl.testing import parameterized from mobly import asserts from net_tests_utils.host.python import apf_test_base, apf_utils from scapy.layers.l2 import Ether +import time # Constants. COUNTER_DROPPED_ETHERTYPE_NOT_ALLOWED = "DROPPED_ETHERTYPE_NOT_ALLOWED" @@ -59,6 +60,9 @@ class ApfV4Test(apf_test_base.ApfTestBase, parameterized.TestCase): # Add zero padding up to minimum ethernet frame length packet = packet.ljust(MIN_PACKET_SIZE * 2, "0") + + # Pause packet sending between tests to avoid APF disablement due to high throughput. + time.sleep(3) self.send_packet_and_expect_counter_increased( packet, COUNTER_DROPPED_ETHERTYPE_NOT_ALLOWED ) diff --git a/tests/cts/multidevices/apfv6_test.py b/tests/cts/multidevices/apfv6_test.py index 9b2e309d1e..c6e5f8de10 100644 --- a/tests/cts/multidevices/apfv6_test.py +++ b/tests/cts/multidevices/apfv6_test.py @@ -79,33 +79,6 @@ class ApfV6Test(apf_test_base.ApfTestBase): arp_request, "DROPPED_ARP_REQUEST_REPLIED", expected_arp_reply ) - def test_broadcast_arp_request_offload(self): - eth = Ether(src=self.server_mac_address, dst='ff:ff:ff:ff:ff:ff') - arp = ARP( - op=1, - psrc=self.server_ipv4_addresses[0], - pdst=self.client_ipv4_addresses[0], - hwsrc=self.server_mac_address - ) - arp_request = bytes(eth/arp).hex() - - eth = Ether(src=self.client_mac_address, dst=self.server_mac_address) - arp = ARP( - op=2, - psrc=self.client_ipv4_addresses[0], - pdst=self.server_ipv4_addresses[0], - hwsrc=self.client_mac_address, - hwdst=self.server_mac_address - ) - expected_arp_reply = bytes(eth/arp).hex() - - # Add zero padding up to 60 bytes, since APFv6 ARP offload always sent out 60 bytes reply - expected_arp_reply = expected_arp_reply.ljust(ARP_OFFLOAD_REPLY_LEN * 2, "0") - - self.send_packet_and_expect_reply_received( - arp_request, "DROPPED_ARP_REQUEST_REPLIED", expected_arp_reply - ) - def test_non_dad_ipv6_neighbor_solicitation_offload(self): eth = Ether(src=self.server_mac_address, dst=self.client_mac_address) ip = IPv6(src=self.server_ipv6_addresses[0], dst=self.client_ipv6_addresses[0]) @@ -158,7 +131,8 @@ class ApfV6Test(apf_test_base.ApfTestBase): @apf_utils.at_least_B() def test_igmpv3_general_query_offload(self): - ether = Ether(src=self.server_mac_address, dst='01:00:5e:00:00:01') + # use unicast to replace multicast ether dst to prevent flaky due to DTIM skip + ether = Ether(src=self.server_mac_address, dst=self.client_mac_address) ip = IP( src=self.server_ipv4_addresses[0], dst='224.0.0.1', @@ -206,7 +180,8 @@ class ApfV6Test(apf_test_base.ApfTestBase): @apf_utils.at_least_B() @apf_utils.apf_ram_at_least(3000) def test_mldv2_general_query_offload(self): - ether = Ether(src=self.server_mac_address, dst='33:33:00:00:00:01') + # use unicast to replace multicast ether dst to prevent flaky due to DTIM skip + ether = Ether(src=self.server_mac_address, dst=self.client_mac_address) ip = IPv6(src=self.server_ipv6_addresses[0], dst='ff02::1', hlim=1) hopOpts = IPv6ExtHdrHopByHop(options=[RouterAlert(otype=5)]) mld = ICMPv6MLQuery2()