[P21] New WifiBridgeApTest
Add first test case
test_two_clients_ping_on_bridged_ap_band_2_and_5_with_wpa3_in_country_us
Bug: b/168305604
Test: locally verified.
Change-Id: I82b0b90f444b769e92859062b1641aa71e651061
diff --git a/acts_tests/acts_contrib/test_utils/wifi/wifi_test_utils.py b/acts_tests/acts_contrib/test_utils/wifi/wifi_test_utils.py
index 0ac7398..ef334eb 100755
--- a/acts_tests/acts_contrib/test_utils/wifi/wifi_test_utils.py
+++ b/acts_tests/acts_contrib/test_utils/wifi/wifi_test_utils.py
@@ -20,6 +20,8 @@
import shutil
import time
+from retry import retry
+
from collections import namedtuple
from enum import IntEnum
from queue import Empty
@@ -2829,3 +2831,77 @@
dut_client.droid.wifiGetConnectionStandard() ==
wifi_constants.WIFI_STANDARD_11AX,
"DUT failed to start SoftAp in 11ax.")
+
+def check_available_channels_in_bands_2_5(dut, country_code):
+ """Check if DUT is capable of enable BridgedAp.
+ #TODO: Find a way to make this function flexible by taking an argument.
+
+ Args:
+ country_code: country code, e.g., 'US', 'JP'.
+ Returns:
+ True: If DUT is capable of enable BridgedAp.
+ False: If DUT is not capable of enable BridgedAp.
+ """
+ set_wifi_country_code(dut, country_code)
+ country = dut.droid.wifiGetCountryCode()
+ dut.log.info("DUT current country code : {}".format(country))
+ # Wi-Fi ON and OFF to make sure country code take effet.
+ wifi_toggle_state(dut, True)
+ wifi_toggle_state(dut, False)
+
+ # Register SoftAp Callback and get SoftAp capability.
+ callbackId = dut.droid.registerSoftApCallback()
+ capability = get_current_softap_capability(dut, callbackId, True)
+ dut.droid.unregisterSoftApCallback(callbackId)
+
+ if capability[wifi_constants.
+ SOFTAP_CAPABILITY_24GHZ_SUPPORTED_CHANNEL_LIST] and \
+ capability[wifi_constants.
+ SOFTAP_CAPABILITY_5GHZ_SUPPORTED_CHANNEL_LIST]:
+ return True
+ return False
+
+
+@retry(tries=5, delay=2)
+def validate_ping_between_two_clients(dut1, dut2):
+ """Make 2 DUT ping each other.
+
+ Args:
+ dut1: An AndroidDevice object.
+ dut2: An AndroidDevice object.
+ """
+ # Get DUTs' IPv4 addresses.
+ dut1_ip = ""
+ dut2_ip = ""
+ try:
+ dut1_ip = dut1.droid.connectivityGetIPv4Addresses('wlan0')[0]
+ except IndexError as e:
+ dut1.log.info(
+ "{} has no Wi-Fi connection, cannot get IPv4 address."
+ .format(dut1.serial))
+ try:
+ dut2_ip = dut2.droid.connectivityGetIPv4Addresses('wlan0')[0]
+ except IndexError as e:
+ dut2.log.info(
+ "{} has no Wi-Fi connection, cannot get IPv4 address."
+ .format(dut2.serial))
+ # Test fail if not able to obtain two DUT's IPv4 addresses.
+ asserts.assert_true(dut1_ip and dut2_ip,
+ "Ping failed because no DUT's IPv4 address")
+
+ dut1.log.info("{} IPv4 addresses : {}".format(dut1.serial, dut1_ip))
+ dut2.log.info("{} IPv4 addresses : {}".format(dut2.serial, dut2_ip))
+
+ # Two clients ping each other
+ dut1.log.info("{} ping {}".format(dut1_ip, dut2_ip))
+ asserts.assert_true(
+ utils.adb_shell_ping(dut1, count=10, dest_ip=dut2_ip,
+ timeout=20),
+ "%s ping %s failed" % (dut1.serial, dut2_ip))
+
+ dut2.log.info("{} ping {}".format(dut2_ip, dut1_ip))
+ asserts.assert_true(
+ utils.adb_shell_ping(dut2, count=10, dest_ip=dut1_ip,
+ timeout=20),
+ "%s ping %s failed" % (dut2.serial, dut1_ip))
+
diff --git a/acts_tests/tests/google/wifi/WifiBridgedApTest.py b/acts_tests/tests/google/wifi/WifiBridgedApTest.py
new file mode 100644
index 0000000..383bf6a
--- /dev/null
+++ b/acts_tests/tests/google/wifi/WifiBridgedApTest.py
@@ -0,0 +1,179 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# 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
+#
+# http://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.
+
+
+import time
+from acts import asserts
+from acts import signals
+from acts.test_decorators import test_tracker_info
+import acts_contrib.test_utils.wifi.wifi_test_utils as wutils
+from acts_contrib.test_utils.wifi import wifi_constants
+from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
+
+WifiEnums = wutils.WifiEnums
+WAIT_BRIDGED_AP_LAUNCH = 5
+
+
+class WifiBridgedApTest(WifiBaseTest):
+ """WiFi BridgedAp test class.
+
+ Test Bed Requirement:
+ * 3 Android devices.
+ """
+
+ def setup_class(self):
+ super().setup_class()
+
+ if len(self.android_devices) == 3:
+ self.dut = self.android_devices[0]
+ self.client1 = self.android_devices[1]
+ self.client2 = self.android_devices[2]
+ else:
+ raise signals.TestAbortClass("WifiBridgedApTest requires 3 DUTs")
+
+ if not self.dut.droid.wifiIsBridgedApConcurrencySupported():
+ raise signals.TestAbortClass("Legacy phone is not supported")
+
+ for ad in self.android_devices:
+ wutils.wifi_test_device_init(ad)
+
+ req_params = ["dbs_supported_models"]
+ opt_param = ["cnss_diag_file", "pixel_models"]
+
+ self.unpack_userparams(
+ req_param_names=req_params, opt_param_names=opt_param)
+
+ def setup_test(self):
+ super().setup_test()
+ for ad in self.android_devices:
+ wutils.reset_wifi(ad)
+ wutils.wifi_toggle_state(self.dut, False)
+ wutils.wifi_toggle_state(self.client1, True)
+ wutils.wifi_toggle_state(self.client2, True)
+
+ def teardown_test(self):
+ super().teardown_test()
+ if self.dut.droid.wifiIsApEnabled():
+ wutils.stop_wifi_tethering(self.dut)
+ for ad in self.android_devices:
+ wutils.reset_wifi(ad)
+ wutils.set_wifi_country_code(
+ ad, wutils.WifiEnums.CountryCode.US)
+
+ def teardown_class(self):
+ super().teardown_class()
+ for ad in self.android_devices:
+ wutils.reset_wifi(ad)
+ if "AccessPoint" in self.user_params:
+ del self.user_params["reference_networks"]
+ del self.user_params["open_network"]
+
+ def two_clients_connect_to_wifi_network(self, dut1, dut2, config):
+ """Connect two clients to different BridgedAp instances.
+ This function will be called only when BridgedAp ON.
+
+ Args:
+ config: Wi-Fi config, e.g., {"SSID": "xxx", "password": "xxx"}
+ Steps:
+ Register SoftAp Callback.
+ Get SoftAp Infos.
+ Get BSSIDs from Infos.
+ Connect two clients to different BridgedAp instances.
+ """
+ # Make sure 2 instances enabled, and get BSSIDs from BridgedAp Infos.
+ callbackId = self.dut.droid.registerSoftApCallback()
+ infos = wutils.get_current_softap_infos(self.dut, callbackId, True)
+ self.dut.droid.unregisterSoftApCallback(callbackId)
+
+ if len(infos) == 0:
+ raise signals.TestFailure("No BridgedAp instance")
+ elif len(infos) == 1:
+ raise signals.TestFailure(
+ "Only one BridgedAp instance, should be two")
+ else:
+ bssid_5g = infos[0][wifi_constants.SOFTAP_INFO_BSSID_CALLBACK_KEY]
+ bssid_2g = infos[1][wifi_constants.SOFTAP_INFO_BSSID_CALLBACK_KEY]
+
+ # Two configs for BridgedAp 2G and 5G instances.
+ config_5g = config.copy()
+ config_2g = config.copy()
+ config_5g[WifiEnums.BSSID_KEY] = bssid_5g
+ config_2g[WifiEnums.BSSID_KEY] = bssid_2g
+
+ # Connect two clients to BridgedAp.
+ wutils.connect_to_wifi_network(dut1, config_5g,
+ check_connectivity=False)
+ wutils.connect_to_wifi_network(dut2, config_2g,
+ check_connectivity=False)
+
+ # Verify if Clients connect to the expected BridgedAp instances.
+ client1_bssid = wutils.get_wlan0_link(
+ self.client1)[wifi_constants.SOFTAP_INFO_BSSID_CALLBACK_KEY]
+ client2_bssid = wutils.get_wlan0_link(
+ self.client2)[wifi_constants.SOFTAP_INFO_BSSID_CALLBACK_KEY]
+ asserts.assert_true(client1_bssid == bssid_5g,
+ "Client1 does not connect to the 5G instance")
+ asserts.assert_true(client2_bssid == bssid_2g,
+ "Client2 does not connect to the 2G instance")
+
+ @test_tracker_info(uuid="6f776b4a-b080-4b52-a330-52aa641b18f2")
+ def test_two_clients_ping_on_bridged_ap_band_2_and_5_with_wpa3_in_country_us(self):
+ """Test clients on different instances can ping each other.
+
+ Steps:
+ Backup config.
+ Make sure clients support WPA3 SAE.
+ Make sure DUT is able to enable BridgedAp.
+ Enable BridgedAp with bridged configuration.
+ RegisterSoftApCallback.
+ Check the bridged AP enabled succeed.
+ Force client#1 connect to 5G.
+ Force client#2 connect to 2.4G.
+ Trigger client#1 and client#2 each other.
+ Restore config.
+ """
+ # Backup config
+ original_softap_config = self.dut.droid.wifiGetApConfiguration()
+
+ # Make sure clients support WPA3 SAE.
+ client1_supported = self.client1.droid.wifiIsWpa3SaeSupported()
+ client2_supported = self.client2.droid.wifiIsWpa3SaeSupported()
+ asserts.skip_if(not (client1_supported and client2_supported),
+ "Clients do not support WPA3 SAE")
+ # Make sure DUT is able to enable BridgedAp.
+ is_supported = wutils.check_available_channels_in_bands_2_5(
+ self.dut, wutils.WifiEnums.CountryCode.US)
+ asserts.skip_if(not is_supported, "BridgedAp is not supported in {}"
+ .format(wutils.WifiEnums.CountryCode.US))
+
+ # Enable BridgedAp
+ config = wutils.create_softap_config()
+ config[WifiEnums.SECURITY] = WifiEnums.SoftApSecurityType.WPA3_SAE
+ wutils.save_wifi_soft_ap_config(
+ self.dut, config,
+ bands=[WifiEnums.WIFI_CONFIG_SOFTAP_BAND_2G,
+ WifiEnums.WIFI_CONFIG_SOFTAP_BAND_2G_5G])
+ wutils.start_wifi_tethering_saved_config(self.dut)
+ # Wait 5 seconds for BridgedAp launch.
+ time.sleep(WAIT_BRIDGED_AP_LAUNCH)
+
+ self.two_clients_connect_to_wifi_network(self.client1, self.client2,
+ config)
+ # Trigger client#1 and client#2 ping each other.
+ wutils.validate_ping_between_two_clients(self.client1, self.client2)
+
+ # Restore config
+ wutils.save_wifi_soft_ap_config(self.dut, original_softap_config)