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 self.passpoint_workflow = "passpoint-login_%s" % self.dut.model 77 78 79 def setup_test(self): 80 self.dut.droid.wakeLockAcquireBright() 81 self.dut.droid.wakeUpNow() 82 self.dut.unlock_screen() 83 84 85 def teardown_test(self): 86 self.dut.droid.wakeLockRelease() 87 self.dut.droid.goToSleepNow() 88 wutils.reset_wifi(self.dut) 89 90 91 def on_fail(self, test_name, begin_time): 92 self.dut.take_bug_report(test_name, begin_time) 93 94 95 """Helper Functions""" 96 97 98 def install_passpoint_profile(self, passpoint_config): 99 """Install the Passpoint network Profile. 100 101 Args: 102 passpoint_config: A JSON dict of the Passpoint configuration. 103 104 """ 105 asserts.assert_true(WifiEnums.SSID_KEY in passpoint_config, 106 "Key '%s' must be present in network definition." % 107 WifiEnums.SSID_KEY) 108 # Install the Passpoint profile. 109 self.dut.droid.addUpdatePasspointConfig(passpoint_config) 110 111 112 def check_passpoint_connection(self, passpoint_network): 113 """Verify the device is automatically able to connect to the Passpoint 114 network. 115 116 Args: 117 passpoint_network: SSID of the Passpoint network. 118 119 """ 120 ad = self.dut 121 ad.ed.clear_all_events() 122 wutils.start_wifi_connection_scan(ad) 123 scan_results = ad.droid.wifiGetScanResults() 124 # Wait for scan to complete. 125 time.sleep(5) 126 ssid = passpoint_network 127 wutils.assert_network_in_list({WifiEnums.SSID_KEY: ssid}, scan_results) 128 # Passpoint network takes longer time to connect than normal networks. 129 # Every try comes with a timeout of 30s. Setting total timeout to 120s. 130 wutils.wifi_passpoint_connect(self.dut, passpoint_network, num_of_tries=4) 131 # Re-verify we are connected to the correct network. 132 network_info = self.dut.droid.wifiGetConnectionInfo() 133 if network_info[WifiEnums.SSID_KEY] != passpoint_network: 134 raise signals.TestFailure("Device did not connect to the passpoint" 135 " network.") 136 137 138 def get_configured_passpoint_and_delete(self): 139 """Get configured Passpoint network and delete using its FQDN.""" 140 passpoint_config = self.dut.droid.getPasspointConfigs() 141 if not len(passpoint_config): 142 raise signals.TestFailure("Failed to fetch the list of configured" 143 "passpoint networks.") 144 if not wutils.delete_passpoint(self.dut, passpoint_config[0]): 145 raise signals.TestFailure("Failed to delete Passpoint configuration" 146 " with FQDN = %s" % passpoint_config[0]) 147 148 def start_subscription_provisioning(self, state): 149 """Start subscription provisioning with a default provider.""" 150 151 self.unpack_userparams(('osu_configs',)) 152 asserts.assert_true( 153 len(self.osu_configs) > 0, 154 "Need at least one osu config.") 155 osu_config = self.osu_configs[OSU_BOINGO] 156 # Clear all previous events. 157 self.dut.ed.clear_all_events() 158 self.dut.droid.startSubscriptionProvisioning(osu_config) 159 start_time = time.time() 160 while time.time() < start_time + OSU_TEST_TIMEOUT: 161 dut_event = self.dut.ed.pop_event("onProvisioningCallback", 162 DEFAULT_TIMEOUT * 18) 163 if dut_event['data']['tag'] == 'success': 164 self.log.info("Passpoint Provisioning Success") 165 # Reset WiFi after provisioning success. 166 if state == RESET: 167 wutils.reset_wifi(self.dut) 168 time.sleep(DEFAULT_TIMEOUT) 169 # Toggle WiFi after provisioning success. 170 elif state == TOGGLE: 171 wutils.toggle_wifi_off_and_on(self.dut) 172 time.sleep(DEFAULT_TIMEOUT) 173 break 174 if dut_event['data']['tag'] == 'failure': 175 raise signals.TestFailure( 176 "Passpoint Provisioning is failed with %s" % 177 dut_event['data'][ 178 'reason']) 179 break 180 if dut_event['data']['tag'] == 'status': 181 self.log.info( 182 "Passpoint Provisioning status %s" % dut_event['data'][ 183 'status']) 184 if int(dut_event['data']['status']) == 7: 185 self.ui.run(self.dut.serial, self.passpoint_workflow) 186 # Clear all previous events. 187 self.dut.ed.clear_all_events() 188 189 # Verify device connects to the Passpoint network. 190 time.sleep(DEFAULT_TIMEOUT) 191 current_passpoint = self.dut.droid.wifiGetConnectionInfo() 192 if current_passpoint[WifiEnums.SSID_KEY] not in osu_config[ 193 "expected_ssids"]: 194 raise signals.TestFailure("Device did not connect to the %s" 195 " passpoint network" % osu_config[ 196 "expected_ssids"]) 197 # Delete the Passpoint profile. 198 self.get_configured_passpoint_and_delete() 199 wutils.wait_for_disconnect(self.dut) 200 201 202 """Tests""" 203 204 @test_tracker_info(uuid="b0bc0153-77bb-4594-8f19-cea2c6bd2f43") 205 def test_add_passpoint_network(self): 206 """Add a Passpoint network and verify device connects to it. 207 208 Steps: 209 1. Install a Passpoint Profile. 210 2. Verify the device connects to the required Passpoint SSID. 211 3. Get the Passpoint configuration added above. 212 4. Delete Passpoint configuration using its FQDN. 213 5. Verify that we are disconnected from the Passpoint network. 214 215 """ 216 passpoint_config = self.passpoint_networks[BOINGO] 217 self.install_passpoint_profile(passpoint_config) 218 ssid = passpoint_config[WifiEnums.SSID_KEY] 219 self.check_passpoint_connection(ssid) 220 self.get_configured_passpoint_and_delete() 221 wutils.wait_for_disconnect(self.dut) 222 223 224 @test_tracker_info(uuid="eb29d6e2-a755-4c9c-9e4e-63ea2277a64a") 225 def test_update_passpoint_network(self): 226 """Update a previous Passpoint network and verify device still connects 227 to it. 228 229 1. Install a Passpoint Profile. 230 2. Verify the device connects to the required Passpoint SSID. 231 3. Update the Passpoint Profile. 232 4. Verify device is still connected to the Passpoint SSID. 233 5. Get the Passpoint configuration added above. 234 6. Delete Passpoint configuration using its FQDN. 235 236 """ 237 passpoint_config = self.passpoint_networks[BOINGO] 238 self.install_passpoint_profile(passpoint_config) 239 ssid = passpoint_config[WifiEnums.SSID_KEY] 240 self.check_passpoint_connection(ssid) 241 242 # Update passpoint configuration using the original profile because we 243 # do not have real profile with updated credentials to use. 244 self.install_passpoint_profile(passpoint_config) 245 246 # Wait for a Disconnect event from the supplicant. 247 wutils.wait_for_disconnect(self.dut) 248 249 # Now check if we are again connected with the updated profile. 250 self.check_passpoint_connection(ssid) 251 252 self.get_configured_passpoint_and_delete() 253 wutils.wait_for_disconnect(self.dut) 254 255 256 @test_tracker_info(uuid="b6e8068d-faa1-49f2-b421-c60defaed5f0") 257 def test_add_delete_list_of_passpoint_network(self): 258 """Add multiple passpoint networks, list them and delete one by one. 259 260 1. Install Passpoint Profile A. 261 2. Install Passpoint Profile B. 262 3. Get all the Passpoint configurations added above and verify. 263 6. Ensure all Passpoint configurations can be deleted. 264 265 """ 266 for passpoint_config in self.passpoint_networks[:2]: 267 self.install_passpoint_profile(passpoint_config) 268 time.sleep(DEFAULT_TIMEOUT) 269 configs = self.dut.droid.getPasspointConfigs() 270 # It is length -1 because ATT profile will be handled separately 271 if not len(configs) or len(configs) != len(self.passpoint_networks[:2]): 272 raise signals.TestFailure("Failed to fetch some or all of the" 273 " configured passpoint networks.") 274 for config in configs: 275 if not wutils.delete_passpoint(self.dut, config): 276 raise signals.TestFailure("Failed to delete Passpoint" 277 " configuration with FQDN = %s" % 278 config) 279 280 281 @test_tracker_info(uuid="a53251be-7aaf-41fc-a5f3-63984269d224") 282 def test_delete_unknown_fqdn(self): 283 """Negative test to delete Passpoint profile using an unknown FQDN. 284 285 1. Pass an unknown FQDN for removal. 286 2. Verify that it was not successful. 287 288 """ 289 if wutils.delete_passpoint(self.dut, self.unknown_fqdn): 290 raise signals.TestFailure("Failed because an unknown FQDN" 291 " was successfully deleted.") 292 293 294 @test_tracker_info(uuid="bf03c03a-e649-4e2b-a557-1f791bd98951") 295 def test_passpoint_failover(self): 296 """Add a pair of passpoint networks and test failover when one of the" 297 profiles is removed. 298 299 1. Install a Passpoint Profile A and B. 300 2. Verify device connects to a Passpoint network and get SSID. 301 3. Delete the current Passpoint profile using its FQDN. 302 4. Verify device fails over and connects to the other Passpoint SSID. 303 5. Delete Passpoint configuration using its FQDN. 304 305 """ 306 # Install both Passpoint profiles on the device. 307 passpoint_ssid = list() 308 for passpoint_config in self.passpoint_networks[:2]: 309 passpoint_ssid.append(passpoint_config[WifiEnums.SSID_KEY]) 310 self.install_passpoint_profile(passpoint_config) 311 time.sleep(DEFAULT_TIMEOUT) 312 313 # Get the current network and the failover network. 314 wutils.wait_for_connect(self.dut) 315 current_passpoint = self.dut.droid.wifiGetConnectionInfo() 316 current_ssid = current_passpoint[WifiEnums.SSID_KEY] 317 if current_ssid not in passpoint_ssid: 318 raise signals.TestFailure("Device did not connect to any of the " 319 "configured Passpoint networks.") 320 321 expected_ssid = self.passpoint_networks[0][WifiEnums.SSID_KEY] 322 if current_ssid == expected_ssid: 323 expected_ssid = self.passpoint_networks[1][WifiEnums.SSID_KEY] 324 325 # Remove the current Passpoint profile. 326 for network in self.passpoint_networks[:2]: 327 if network[WifiEnums.SSID_KEY] == current_ssid: 328 if not wutils.delete_passpoint(self.dut, network["fqdn"]): 329 raise signals.TestFailure("Failed to delete Passpoint" 330 " configuration with FQDN = %s" % 331 network["fqdn"]) 332 # Verify device fails over and connects to the other passpoint network. 333 time.sleep(DEFAULT_TIMEOUT) 334 335 current_passpoint = self.dut.droid.wifiGetConnectionInfo() 336 if current_passpoint[WifiEnums.SSID_KEY] != expected_ssid: 337 raise signals.TestFailure("Device did not failover to the %s" 338 " passpoint network" % expected_ssid) 339 340 # Delete the remaining Passpoint profile. 341 self.get_configured_passpoint_and_delete() 342 wutils.wait_for_disconnect(self.dut) 343 344 345 def test_install_att_passpoint_profile(self): 346 """Add an AT&T Passpoint profile. 347 348 It is used for only installing the profile for other tests. 349 """ 350 isFound = False 351 for passpoint_config in self.passpoint_networks: 352 if 'att' in passpoint_config['fqdn']: 353 isFound = True 354 self.install_passpoint_profile(passpoint_config) 355 break 356 if not isFound: 357 raise signals.TestFailure("cannot find ATT profile.") 358 359 360 @test_tracker_info(uuid="e3e826d2-7c39-4c37-ab3f-81992d5aa0e8") 361 def test_att_passpoint_network(self): 362 """Add a AT&T Passpoint network and verify device connects to it. 363 364 Steps: 365 1. Install a AT&T Passpoint Profile. 366 2. Verify the device connects to the required Passpoint SSID. 367 3. Get the Passpoint configuration added above. 368 4. Delete Passpoint configuration using its FQDN. 369 5. Verify that we are disconnected from the Passpoint network. 370 371 """ 372 carriers = ["att"] 373 operator = get_operator_name(self.log, self.dut) 374 asserts.skip_if(operator not in carriers, 375 "Device %s does not have a ATT sim" % self.dut.model) 376 377 passpoint_config = self.passpoint_networks[ATT] 378 self.install_passpoint_profile(passpoint_config) 379 ssid = passpoint_config[WifiEnums.SSID_KEY] 380 self.check_passpoint_connection(ssid) 381 self.get_configured_passpoint_and_delete() 382 wutils.wait_for_disconnect(self.dut) 383 384 385 @test_tracker_info(uuid="c85c81b2-7133-4635-8328-9498169ae802") 386 def test_start_subscription_provisioning(self): 387 self.start_subscription_provisioning(0) 388 389 390 @test_tracker_info(uuid="fd09a643-0d4b-45a9-881a-a771f9707ab1") 391 def test_start_subscription_provisioning_and_reset_wifi(self): 392 self.start_subscription_provisioning(RESET) 393 394 395 @test_tracker_info(uuid="f43ea759-673f-4567-aa11-da3bc2cabf08") 396 def test_start_subscription_provisioning_and_toggle_wifi(self): 397 self.start_subscription_provisioning(TOGGLE) 398