1#!/usr/bin/env python3.4 2# 3# Copyright 2017 - The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17import itertools 18import pprint 19import queue 20import time 21 22import acts.base_test 23import acts.test_utils.wifi.wifi_test_utils as wutils 24 25 26import WifiManagerTest 27from acts import asserts 28from acts import signals 29from acts.libs.uicd.uicd_cli import UicdCli 30from acts.libs.uicd.uicd_cli import UicdError 31from acts.test_decorators import test_tracker_info 32from acts.test_utils.tel.tel_test_utils import get_operator_name 33from acts.utils import force_airplane_mode 34 35WifiEnums = wutils.WifiEnums 36 37DEFAULT_TIMEOUT = 10 38OSU_TEST_TIMEOUT = 300 39 40# Constants for providers. 41GLOBAL_RE = 0 42OSU_BOINGO = 0 43BOINGO = 1 44ATT = 2 45 46# Constants used for various device operations. 47RESET = 1 48TOGGLE = 2 49 50UNKNOWN_FQDN = "@#@@!00fffffx" 51 52class WifiPasspointTest(acts.base_test.BaseTestClass): 53 """Tests for APIs in Android's WifiManager class. 54 55 Test Bed Requirement: 56 * One Android device 57 * Several Wi-Fi networks visible to the device, including an open Wi-Fi 58 network. 59 """ 60 61 def setup_class(self): 62 self.dut = self.android_devices[0] 63 wutils.wifi_test_device_init(self.dut) 64 req_params = ["passpoint_networks", "uicd_workflows", "uicd_zip"] 65 opt_param = [] 66 self.unpack_userparams( 67 req_param_names=req_params, opt_param_names=opt_param) 68 self.unpack_userparams(req_params) 69 asserts.assert_true( 70 len(self.passpoint_networks) > 0, 71 "Need at least one Passpoint network.") 72 wutils.wifi_toggle_state(self.dut, True) 73 self.unknown_fqdn = UNKNOWN_FQDN 74 # Setup Uicd cli object for UI interation. 75 self.ui = UicdCli(self.uicd_zip[0], self.uicd_workflows) 76 77 78 def setup_test(self): 79 self.dut.droid.wakeLockAcquireBright() 80 self.dut.droid.wakeUpNow() 81 82 83 def teardown_test(self): 84 self.dut.droid.wakeLockRelease() 85 self.dut.droid.goToSleepNow() 86 wutils.reset_wifi(self.dut) 87 88 89 def on_fail(self, test_name, begin_time): 90 self.dut.take_bug_report(test_name, begin_time) 91 92 93 """Helper Functions""" 94 95 96 def install_passpoint_profile(self, passpoint_config): 97 """Install the Passpoint network Profile. 98 99 Args: 100 passpoint_config: A JSON dict of the Passpoint configuration. 101 102 """ 103 asserts.assert_true(WifiEnums.SSID_KEY in passpoint_config, 104 "Key '%s' must be present in network definition." % 105 WifiEnums.SSID_KEY) 106 # Install the Passpoint profile. 107 self.dut.droid.addUpdatePasspointConfig(passpoint_config) 108 109 110 def check_passpoint_connection(self, passpoint_network): 111 """Verify the device is automatically able to connect to the Passpoint 112 network. 113 114 Args: 115 passpoint_network: SSID of the Passpoint network. 116 117 """ 118 ad = self.dut 119 ad.ed.clear_all_events() 120 wutils.start_wifi_connection_scan(ad) 121 scan_results = ad.droid.wifiGetScanResults() 122 # Wait for scan to complete. 123 time.sleep(5) 124 ssid = passpoint_network 125 wutils.assert_network_in_list({WifiEnums.SSID_KEY: ssid}, scan_results) 126 # Passpoint network takes longer time to connect than normal networks. 127 # Every try comes with a timeout of 30s. Setting total timeout to 120s. 128 wutils.wifi_passpoint_connect(self.dut, passpoint_network, num_of_tries=4) 129 # Re-verify we are connected to the correct network. 130 network_info = self.dut.droid.wifiGetConnectionInfo() 131 if network_info[WifiEnums.SSID_KEY] != passpoint_network: 132 raise signals.TestFailure("Device did not connect to the passpoint" 133 " network.") 134 135 136 def get_configured_passpoint_and_delete(self): 137 """Get configured Passpoint network and delete using its FQDN.""" 138 passpoint_config = self.dut.droid.getPasspointConfigs() 139 if not len(passpoint_config): 140 raise signals.TestFailure("Failed to fetch the list of configured" 141 "passpoint networks.") 142 if not wutils.delete_passpoint(self.dut, passpoint_config[0]): 143 raise signals.TestFailure("Failed to delete Passpoint configuration" 144 " with FQDN = %s" % passpoint_config[0]) 145 146 def start_subscription_provisioning(self, state): 147 """Start subscription provisioning with a default provider.""" 148 149 self.unpack_userparams(('osu_configs',)) 150 asserts.assert_true( 151 len(self.osu_configs) > 0, 152 "Need at least one osu config.") 153 osu_config = self.osu_configs[OSU_BOINGO] 154 # Clear all previous events. 155 self.dut.ed.clear_all_events() 156 self.dut.droid.startSubscriptionProvisioning(osu_config) 157 start_time = time.time() 158 while time.time() < start_time + OSU_TEST_TIMEOUT: 159 dut_event = self.dut.ed.pop_event("onProvisioningCallback", 160 DEFAULT_TIMEOUT * 18) 161 if dut_event['data']['tag'] == 'success': 162 self.log.info("Passpoint Provisioning Success") 163 # Reset WiFi after provisioning success. 164 if state == RESET: 165 wutils.reset_wifi(self.dut) 166 time.sleep(DEFAULT_TIMEOUT) 167 # Toggle WiFi after provisioning success. 168 elif state == TOGGLE: 169 wutils.toggle_wifi_off_and_on(self.dut) 170 time.sleep(DEFAULT_TIMEOUT) 171 break 172 if dut_event['data']['tag'] == 'failure': 173 raise signals.TestFailure( 174 "Passpoint Provisioning is failed with %s" % 175 dut_event['data'][ 176 'reason']) 177 break 178 if dut_event['data']['tag'] == 'status': 179 self.log.info( 180 "Passpoint Provisioning status %s" % dut_event['data'][ 181 'status']) 182 if int(dut_event['data']['status']) == 7: 183 self.ui.run(self.dut.serial, "passpoint-login") 184 # Clear all previous events. 185 self.dut.ed.clear_all_events() 186 187 # Verify device connects to the Passpoint network. 188 time.sleep(DEFAULT_TIMEOUT) 189 current_passpoint = self.dut.droid.wifiGetConnectionInfo() 190 if current_passpoint[WifiEnums.SSID_KEY] not in osu_config[ 191 "expected_ssids"]: 192 raise signals.TestFailure("Device did not connect to the %s" 193 " passpoint network" % osu_config[ 194 "expected_ssids"]) 195 # Delete the Passpoint profile. 196 self.get_configured_passpoint_and_delete() 197 wutils.wait_for_disconnect(self.dut) 198 199 200 """Tests""" 201 202 @test_tracker_info(uuid="b0bc0153-77bb-4594-8f19-cea2c6bd2f43") 203 def test_add_passpoint_network(self): 204 """Add a Passpoint network and verify device connects to it. 205 206 Steps: 207 1. Install a Passpoint Profile. 208 2. Verify the device connects to the required Passpoint SSID. 209 3. Get the Passpoint configuration added above. 210 4. Delete Passpoint configuration using its FQDN. 211 5. Verify that we are disconnected from the Passpoint network. 212 213 """ 214 passpoint_config = self.passpoint_networks[BOINGO] 215 self.install_passpoint_profile(passpoint_config) 216 ssid = passpoint_config[WifiEnums.SSID_KEY] 217 self.check_passpoint_connection(ssid) 218 self.get_configured_passpoint_and_delete() 219 wutils.wait_for_disconnect(self.dut) 220 221 222 @test_tracker_info(uuid="eb29d6e2-a755-4c9c-9e4e-63ea2277a64a") 223 def test_update_passpoint_network(self): 224 """Update a previous Passpoint network and verify device still connects 225 to it. 226 227 1. Install a Passpoint Profile. 228 2. Verify the device connects to the required Passpoint SSID. 229 3. Update the Passpoint Profile. 230 4. Verify device is still connected to the Passpoint SSID. 231 5. Get the Passpoint configuration added above. 232 6. Delete Passpoint configuration using its FQDN. 233 234 """ 235 passpoint_config = self.passpoint_networks[BOINGO] 236 self.install_passpoint_profile(passpoint_config) 237 ssid = passpoint_config[WifiEnums.SSID_KEY] 238 self.check_passpoint_connection(ssid) 239 240 # Update passpoint configuration using the original profile because we 241 # do not have real profile with updated credentials to use. 242 self.install_passpoint_profile(passpoint_config) 243 244 # Wait for a Disconnect event from the supplicant. 245 wutils.wait_for_disconnect(self.dut) 246 247 # Now check if we are again connected with the updated profile. 248 self.check_passpoint_connection(ssid) 249 250 self.get_configured_passpoint_and_delete() 251 wutils.wait_for_disconnect(self.dut) 252 253 254 @test_tracker_info(uuid="b6e8068d-faa1-49f2-b421-c60defaed5f0") 255 def test_add_delete_list_of_passpoint_network(self): 256 """Add multiple passpoint networks, list them and delete one by one. 257 258 1. Install Passpoint Profile A. 259 2. Install Passpoint Profile B. 260 3. Get all the Passpoint configurations added above and verify. 261 6. Ensure all Passpoint configurations can be deleted. 262 263 """ 264 for passpoint_config in self.passpoint_networks[:2]: 265 self.install_passpoint_profile(passpoint_config) 266 time.sleep(DEFAULT_TIMEOUT) 267 configs = self.dut.droid.getPasspointConfigs() 268 # It is length -1 because ATT profile will be handled separately 269 if not len(configs) or len(configs) != len(self.passpoint_networks[:2]): 270 raise signals.TestFailure("Failed to fetch some or all of the" 271 " configured passpoint networks.") 272 for config in configs: 273 if not wutils.delete_passpoint(self.dut, config): 274 raise signals.TestFailure("Failed to delete Passpoint" 275 " configuration with FQDN = %s" % 276 config) 277 278 279 @test_tracker_info(uuid="a53251be-7aaf-41fc-a5f3-63984269d224") 280 def test_delete_unknown_fqdn(self): 281 """Negative test to delete Passpoint profile using an unknown FQDN. 282 283 1. Pass an unknown FQDN for removal. 284 2. Verify that it was not successful. 285 286 """ 287 if wutils.delete_passpoint(self.dut, self.unknown_fqdn): 288 raise signals.TestFailure("Failed because an unknown FQDN" 289 " was successfully deleted.") 290 291 292 @test_tracker_info(uuid="bf03c03a-e649-4e2b-a557-1f791bd98951") 293 def test_passpoint_failover(self): 294 """Add a pair of passpoint networks and test failover when one of the" 295 profiles is removed. 296 297 1. Install a Passpoint Profile A and B. 298 2. Verify device connects to a Passpoint network and get SSID. 299 3. Delete the current Passpoint profile using its FQDN. 300 4. Verify device fails over and connects to the other Passpoint SSID. 301 5. Delete Passpoint configuration using its FQDN. 302 303 """ 304 # Install both Passpoint profiles on the device. 305 passpoint_ssid = list() 306 for passpoint_config in self.passpoint_networks[:2]: 307 passpoint_ssid.append(passpoint_config[WifiEnums.SSID_KEY]) 308 self.install_passpoint_profile(passpoint_config) 309 time.sleep(DEFAULT_TIMEOUT) 310 311 # Get the current network and the failover network. 312 wutils.wait_for_connect(self.dut) 313 current_passpoint = self.dut.droid.wifiGetConnectionInfo() 314 current_ssid = current_passpoint[WifiEnums.SSID_KEY] 315 if current_ssid not in passpoint_ssid: 316 raise signals.TestFailure("Device did not connect to any of the " 317 "configured Passpoint networks.") 318 319 expected_ssid = self.passpoint_networks[0][WifiEnums.SSID_KEY] 320 if current_ssid == expected_ssid: 321 expected_ssid = self.passpoint_networks[1][WifiEnums.SSID_KEY] 322 323 # Remove the current Passpoint profile. 324 for network in self.passpoint_networks[:2]: 325 if network[WifiEnums.SSID_KEY] == current_ssid: 326 if not wutils.delete_passpoint(self.dut, network["fqdn"]): 327 raise signals.TestFailure("Failed to delete Passpoint" 328 " configuration with FQDN = %s" % 329 network["fqdn"]) 330 # Verify device fails over and connects to the other passpoint network. 331 time.sleep(DEFAULT_TIMEOUT) 332 333 current_passpoint = self.dut.droid.wifiGetConnectionInfo() 334 if current_passpoint[WifiEnums.SSID_KEY] != expected_ssid: 335 raise signals.TestFailure("Device did not failover to the %s" 336 " passpoint network" % expected_ssid) 337 338 # Delete the remaining Passpoint profile. 339 self.get_configured_passpoint_and_delete() 340 wutils.wait_for_disconnect(self.dut) 341 342 343 def test_install_att_passpoint_profile(self): 344 """Add an AT&T Passpoint profile. 345 346 It is used for only installing the profile for other tests. 347 """ 348 isFound = False 349 for passpoint_config in self.passpoint_networks: 350 if 'att' in passpoint_config['fqdn']: 351 isFound = True 352 self.install_passpoint_profile(passpoint_config) 353 break 354 if not isFound: 355 raise signals.TestFailure("cannot find ATT profile.") 356 357 358 @test_tracker_info(uuid="e3e826d2-7c39-4c37-ab3f-81992d5aa0e8") 359 def test_att_passpoint_network(self): 360 """Add a AT&T Passpoint network and verify device connects to it. 361 362 Steps: 363 1. Install a AT&T Passpoint Profile. 364 2. Verify the device connects to the required Passpoint SSID. 365 3. Get the Passpoint configuration added above. 366 4. Delete Passpoint configuration using its FQDN. 367 5. Verify that we are disconnected from the Passpoint network. 368 369 """ 370 carriers = ["att"] 371 operator = get_operator_name(self.log, self.dut) 372 asserts.skip_if(operator not in carriers, 373 "Device %s does not have a ATT sim" % self.dut.model) 374 375 passpoint_config = self.passpoint_networks[ATT] 376 self.install_passpoint_profile(passpoint_config) 377 ssid = passpoint_config[WifiEnums.SSID_KEY] 378 self.check_passpoint_connection(ssid) 379 self.get_configured_passpoint_and_delete() 380 wutils.wait_for_disconnect(self.dut) 381 382 383 @test_tracker_info(uuid="c85c81b2-7133-4635-8328-9498169ae802") 384 def test_start_subscription_provisioning(self): 385 self.start_subscription_provisioning(0) 386 387 388 @test_tracker_info(uuid="fd09a643-0d4b-45a9-881a-a771f9707ab1") 389 def test_start_subscription_provisioning_and_reset_wifi(self): 390 self.start_subscription_provisioning(RESET) 391 392 393 @test_tracker_info(uuid="f43ea759-673f-4567-aa11-da3bc2cabf08") 394 def test_start_subscription_provisioning_and_toggle_wifi(self): 395 self.start_subscription_provisioning(TOGGLE) 396