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