• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
22from acts.test_utils.net import ui_utils as uutils
23import acts.test_utils.wifi.wifi_test_utils as wutils
24from acts.test_utils.wifi.WifiBaseTest import WifiBaseTest
25
26
27from acts import asserts
28from acts import signals
29from acts.test_decorators import test_tracker_info
30from acts.test_utils.tel.tel_test_utils import get_operator_name
31from acts.test_utils.wifi.WifiBaseTest import WifiBaseTest
32from acts.utils import force_airplane_mode
33
34WifiEnums = wutils.WifiEnums
35
36DEFAULT_TIMEOUT = 10
37OSU_TEST_TIMEOUT = 300
38
39# Constants for providers.
40GLOBAL_RE = 0
41OSU_BOINGO = 0
42BOINGO = 1
43ATT = 2
44
45# Constants used for various device operations.
46RESET = 1
47TOGGLE = 2
48
49UNKNOWN_FQDN = "@#@@!00fffffx"
50
51# Constants for Boingo UI automator
52EDIT_TEXT_CLASS_NAME = "android.widget.EditText"
53PASSWORD_TEXT = "Password"
54PASSPOINT_BUTTON = "Get Passpoint"
55BOINGO_UI_TEXT = "Online Sign Up"
56
57class WifiPasspointTest(WifiBaseTest):
58    """Tests for APIs in Android's WifiManager class.
59
60    Test Bed Requirement:
61    * One Android device
62    * Several Wi-Fi networks visible to the device, including an open Wi-Fi
63      network.
64    """
65
66    def setup_class(self):
67        super().setup_class()
68        self.dut = self.android_devices[0]
69        wutils.wifi_test_device_init(self.dut)
70        req_params = ["passpoint_networks",
71                      "boingo_username",
72                      "boingo_password",]
73        self.unpack_userparams(req_param_names=req_params,)
74        asserts.assert_true(
75            len(self.passpoint_networks) > 0,
76            "Need at least one Passpoint network.")
77        wutils.wifi_toggle_state(self.dut, True)
78        self.unknown_fqdn = UNKNOWN_FQDN
79
80
81    def setup_test(self):
82        super().setup_test()
83        self.dut.droid.wakeLockAcquireBright()
84        self.dut.droid.wakeUpNow()
85        self.dut.unlock_screen()
86
87
88    def teardown_test(self):
89        super().teardown_test()
90        self.dut.droid.wakeLockRelease()
91        self.dut.droid.goToSleepNow()
92        passpoint_configs = self.dut.droid.getPasspointConfigs()
93        for config in passpoint_configs:
94            wutils.delete_passpoint(self.dut, config)
95        wutils.reset_wifi(self.dut)
96
97    """Helper Functions"""
98
99
100    def install_passpoint_profile(self, passpoint_config):
101        """Install the Passpoint network Profile.
102
103        Args:
104            passpoint_config: A JSON dict of the Passpoint configuration.
105
106        """
107        asserts.assert_true(WifiEnums.SSID_KEY in passpoint_config,
108                "Key '%s' must be present in network definition." %
109                WifiEnums.SSID_KEY)
110        # Install the Passpoint profile.
111        self.dut.droid.addUpdatePasspointConfig(passpoint_config)
112
113
114    def check_passpoint_connection(self, passpoint_network):
115        """Verify the device is automatically able to connect to the Passpoint
116           network.
117
118           Args:
119               passpoint_network: SSID of the Passpoint network.
120
121        """
122        ad = self.dut
123        ad.ed.clear_all_events()
124        try:
125            wutils.start_wifi_connection_scan_and_return_status(ad)
126            wutils.wait_for_connect(ad)
127        except:
128            pass
129        # Re-verify we are connected to the correct network.
130        network_info = self.dut.droid.wifiGetConnectionInfo()
131        self.log.info("Network Info: %s" % network_info)
132        if not network_info or not network_info[WifiEnums.SSID_KEY] or \
133            network_info[WifiEnums.SSID_KEY] not in passpoint_network:
134              raise signals.TestFailure(
135                  "Device did not connect to passpoint 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 ui_automator_boingo(self):
149        """Run UI automator for boingo passpoint."""
150        # Verify the boingo login page shows
151        asserts.assert_true(
152            uutils.has_element(self.dut, text=BOINGO_UI_TEXT),
153            "Failed to launch boingohotspot login page")
154
155        # Go to the bottom of the page
156        for _ in range(3):
157            self.dut.adb.shell("input swipe 300 900 300 300")
158
159        # Enter username
160        uutils.wait_and_input_text(self.dut,
161                                   input_text=self.boingo_username,
162                                   text="",
163                                   class_name=EDIT_TEXT_CLASS_NAME)
164        self.dut.adb.shell("input keyevent 111")  # collapse keyboard
165        self.dut.adb.shell("input swipe 300 900 300 750")  # swipe up to show text
166
167        # Enter password
168        uutils.wait_and_input_text(self.dut,
169                                   input_text=self.boingo_password,
170                                   text=PASSWORD_TEXT)
171        self.dut.adb.shell("input keyevent 111")  # collapse keyboard
172        self.dut.adb.shell("input swipe 300 900 300 750")  # swipe up to show text
173
174        # Login
175        uutils.wait_and_click(self.dut, text=PASSPOINT_BUTTON)
176        time.sleep(DEFAULT_TIMEOUT)
177
178    def start_subscription_provisioning(self, state):
179        """Start subscription provisioning with a default provider."""
180
181        self.unpack_userparams(('osu_configs',))
182        asserts.assert_true(
183            len(self.osu_configs) > 0,
184            "Need at least one osu config.")
185        osu_config = self.osu_configs[OSU_BOINGO]
186        # Clear all previous events.
187        self.dut.ed.clear_all_events()
188        self.dut.droid.startSubscriptionProvisioning(osu_config)
189        start_time = time.time()
190        while time.time() < start_time + OSU_TEST_TIMEOUT:
191            dut_event = self.dut.ed.pop_event("onProvisioningCallback",
192                                              DEFAULT_TIMEOUT * 18)
193            if dut_event['data']['tag'] == 'success':
194                self.log.info("Passpoint Provisioning Success")
195                # Reset WiFi after provisioning success.
196                if state == RESET:
197                    wutils.reset_wifi(self.dut)
198                    time.sleep(DEFAULT_TIMEOUT)
199                # Toggle WiFi after provisioning success.
200                elif state == TOGGLE:
201                    wutils.toggle_wifi_off_and_on(self.dut)
202                    time.sleep(DEFAULT_TIMEOUT)
203                break
204            if dut_event['data']['tag'] == 'failure':
205                raise signals.TestFailure(
206                    "Passpoint Provisioning is failed with %s" %
207                    dut_event['data'][
208                        'reason'])
209                break
210            if dut_event['data']['tag'] == 'status':
211                self.log.info(
212                    "Passpoint Provisioning status %s" % dut_event['data'][
213                        'status'])
214                if int(dut_event['data']['status']) == 7:
215                    self.ui_automator_boingo()
216        # Clear all previous events.
217        self.dut.ed.clear_all_events()
218
219        # Verify device connects to the Passpoint network.
220        time.sleep(DEFAULT_TIMEOUT)
221        current_passpoint = self.dut.droid.wifiGetConnectionInfo()
222        if current_passpoint[WifiEnums.SSID_KEY] not in osu_config[
223            "expected_ssids"]:
224            raise signals.TestFailure("Device did not connect to the %s"
225                                      " passpoint network" % osu_config[
226                                          "expected_ssids"])
227        # Delete the Passpoint profile.
228        self.get_configured_passpoint_and_delete()
229        wutils.wait_for_disconnect(self.dut)
230
231
232    """Tests"""
233
234    @test_tracker_info(uuid="b0bc0153-77bb-4594-8f19-cea2c6bd2f43")
235    def test_add_passpoint_network(self):
236        """Add a Passpoint network and verify device connects to it.
237
238        Steps:
239            1. Install a Passpoint Profile.
240            2. Verify the device connects to the required Passpoint SSID.
241            3. Get the Passpoint configuration added above.
242            4. Delete Passpoint configuration using its FQDN.
243            5. Verify that we are disconnected from the Passpoint network.
244
245        """
246        passpoint_config = self.passpoint_networks[BOINGO]
247        self.install_passpoint_profile(passpoint_config)
248        ssid = passpoint_config[WifiEnums.SSID_KEY]
249        self.check_passpoint_connection(ssid)
250        self.get_configured_passpoint_and_delete()
251        wutils.wait_for_disconnect(self.dut)
252
253
254    @test_tracker_info(uuid="eb29d6e2-a755-4c9c-9e4e-63ea2277a64a")
255    def test_update_passpoint_network(self):
256        """Update a previous Passpoint network and verify device still connects
257           to it.
258
259        1. Install a Passpoint Profile.
260        2. Verify the device connects to the required Passpoint SSID.
261        3. Update the Passpoint Profile.
262        4. Verify device is still connected to the Passpoint SSID.
263        5. Get the Passpoint configuration added above.
264        6. Delete Passpoint configuration using its FQDN.
265
266        """
267        passpoint_config = self.passpoint_networks[BOINGO]
268        self.install_passpoint_profile(passpoint_config)
269        ssid = passpoint_config[WifiEnums.SSID_KEY]
270        self.check_passpoint_connection(ssid)
271
272        # Update passpoint configuration using the original profile because we
273        # do not have real profile with updated credentials to use.
274        self.install_passpoint_profile(passpoint_config)
275
276        # Wait for a Disconnect event from the supplicant.
277        wutils.wait_for_disconnect(self.dut)
278
279        # Now check if we are again connected with the updated profile.
280        self.check_passpoint_connection(ssid)
281
282        self.get_configured_passpoint_and_delete()
283        wutils.wait_for_disconnect(self.dut)
284
285
286    @test_tracker_info(uuid="b6e8068d-faa1-49f2-b421-c60defaed5f0")
287    def test_add_delete_list_of_passpoint_network(self):
288        """Add multiple passpoint networks, list them and delete one by one.
289
290        1. Install Passpoint Profile A.
291        2. Install Passpoint Profile B.
292        3. Get all the Passpoint configurations added above and verify.
293        6. Ensure all Passpoint configurations can be deleted.
294
295        """
296        for passpoint_config in self.passpoint_networks[:2]:
297            self.install_passpoint_profile(passpoint_config)
298            time.sleep(DEFAULT_TIMEOUT)
299        configs = self.dut.droid.getPasspointConfigs()
300        #  It is length -1 because ATT profile will be handled separately
301        if not len(configs) or len(configs) != len(self.passpoint_networks[:2]):
302            raise signals.TestFailure("Failed to fetch some or all of the"
303                                      " configured passpoint networks.")
304        for config in configs:
305            if not wutils.delete_passpoint(self.dut, config):
306                raise signals.TestFailure("Failed to delete Passpoint"
307                                          " configuration with FQDN = %s" %
308                                          config)
309
310
311    @test_tracker_info(uuid="a53251be-7aaf-41fc-a5f3-63984269d224")
312    def test_delete_unknown_fqdn(self):
313        """Negative test to delete Passpoint profile using an unknown FQDN.
314
315        1. Pass an unknown FQDN for removal.
316        2. Verify that it was not successful.
317
318        """
319        if wutils.delete_passpoint(self.dut, self.unknown_fqdn):
320            raise signals.TestFailure("Failed because an unknown FQDN"
321                                      " was successfully deleted.")
322
323
324    @test_tracker_info(uuid="bf03c03a-e649-4e2b-a557-1f791bd98951")
325    def test_passpoint_failover(self):
326        """Add a pair of passpoint networks and test failover when one of the"
327           profiles is removed.
328
329        1. Install a Passpoint Profile A and B.
330        2. Verify device connects to a Passpoint network and get SSID.
331        3. Delete the current Passpoint profile using its FQDN.
332        4. Verify device fails over and connects to the other Passpoint SSID.
333        5. Delete Passpoint configuration using its FQDN.
334
335        """
336        # Install both Passpoint profiles on the device.
337        passpoint_ssid = list()
338        for passpoint_config in self.passpoint_networks[:2]:
339            passpoint_ssid.extend(passpoint_config[WifiEnums.SSID_KEY])
340            self.install_passpoint_profile(passpoint_config)
341            time.sleep(DEFAULT_TIMEOUT)
342
343        # Get the current network and the failover network.
344        wutils.wait_for_connect(self.dut)
345        current_passpoint = self.dut.droid.wifiGetConnectionInfo()
346        current_ssid = current_passpoint[WifiEnums.SSID_KEY]
347        if current_ssid not in passpoint_ssid:
348           raise signals.TestFailure("Device did not connect to any of the "
349                                     "configured Passpoint networks.")
350
351        expected_ssid =  self.passpoint_networks[0][WifiEnums.SSID_KEY]
352        if current_ssid in expected_ssid:
353            expected_ssid = self.passpoint_networks[1][WifiEnums.SSID_KEY]
354
355        # Remove the current Passpoint profile.
356        for network in self.passpoint_networks[:2]:
357            if current_ssid in network[WifiEnums.SSID_KEY]:
358                if not wutils.delete_passpoint(self.dut, network["fqdn"]):
359                    raise signals.TestFailure("Failed to delete Passpoint"
360                                              " configuration with FQDN = %s" %
361                                              network["fqdn"])
362        # Verify device fails over and connects to the other passpoint network.
363        time.sleep(DEFAULT_TIMEOUT)
364
365        current_passpoint = self.dut.droid.wifiGetConnectionInfo()
366        if current_passpoint[WifiEnums.SSID_KEY] not in expected_ssid:
367            raise signals.TestFailure("Device did not failover to the %s"
368                                      " passpoint network" % expected_ssid)
369
370        # Delete the remaining Passpoint profile.
371        self.get_configured_passpoint_and_delete()
372        wutils.wait_for_disconnect(self.dut)
373
374
375    @test_tracker_info(uuid="37ae0223-0cb7-43f3-8ba8-474fad6e4b71")
376    def test_install_att_passpoint_profile(self):
377        """Add an AT&T Passpoint profile.
378
379        It is used for only installing the profile for other tests.
380        """
381        isFound = False
382        for passpoint_config in self.passpoint_networks:
383            if 'att' in passpoint_config['fqdn']:
384                isFound = True
385                self.install_passpoint_profile(passpoint_config)
386                break
387        if not isFound:
388            raise signals.TestFailure("cannot find ATT profile.")
389
390
391    @test_tracker_info(uuid="e3e826d2-7c39-4c37-ab3f-81992d5aa0e8")
392    @WifiBaseTest.wifi_test_wrap
393    def test_att_passpoint_network(self):
394        """Add a AT&T Passpoint network and verify device connects to it.
395
396        Steps:
397            1. Install a AT&T Passpoint Profile.
398            2. Verify the device connects to the required Passpoint SSID.
399            3. Get the Passpoint configuration added above.
400            4. Delete Passpoint configuration using its FQDN.
401            5. Verify that we are disconnected from the Passpoint network.
402
403        """
404        carriers = ["att"]
405        operator = get_operator_name(self.log, self.dut)
406        asserts.skip_if(operator not in carriers,
407                        "Device %s does not have a ATT sim" % self.dut.model)
408
409        passpoint_config = self.passpoint_networks[ATT]
410        self.install_passpoint_profile(passpoint_config)
411        ssid = passpoint_config[WifiEnums.SSID_KEY]
412        self.check_passpoint_connection(ssid)
413        self.get_configured_passpoint_and_delete()
414        wutils.wait_for_disconnect(self.dut)
415
416
417    @test_tracker_info(uuid="c85c81b2-7133-4635-8328-9498169ae802")
418    def test_start_subscription_provisioning(self):
419        self.start_subscription_provisioning(0)
420
421
422    @test_tracker_info(uuid="fd09a643-0d4b-45a9-881a-a771f9707ab1")
423    def test_start_subscription_provisioning_and_reset_wifi(self):
424        self.start_subscription_provisioning(RESET)
425
426
427    @test_tracker_info(uuid="f43ea759-673f-4567-aa11-da3bc2cabf08")
428    def test_start_subscription_provisioning_and_toggle_wifi(self):
429        self.start_subscription_provisioning(TOGGLE)
430
431    @test_tracker_info(uuid="ad6d5eb8-a3c5-4ce0-9e10-d0f201cd0f40")
432    def test_user_override_auto_join_on_passpoint_network(self):
433        """Add a Passpoint network, simulate user change the auto join to false, ensure the device
434        doesn't auto connect to this passponit network
435
436        Steps:
437            1. Install a Passpoint Profile.
438            2. Verify the device connects to the required Passpoint SSID.
439            3. Disable auto join Passpoint configuration using its FQDN.
440            4. disable and enable Wifi toggle, ensure we don't connect back
441        """
442        passpoint_config = self.passpoint_networks[BOINGO]
443        self.install_passpoint_profile(passpoint_config)
444        ssid = passpoint_config[WifiEnums.SSID_KEY]
445        self.check_passpoint_connection(ssid)
446        self.dut.log.info("Disable auto join on passpoint")
447        self.dut.droid.wifiEnableAutojoinPasspoint(passpoint_config['fqdn'], False)
448        wutils.wifi_toggle_state(self.dut, False)
449        wutils.wifi_toggle_state(self.dut, True)
450        asserts.assert_false(
451            wutils.wait_for_connect(self.dut, ssid, assert_on_fail=False),
452            "Device should not connect.")
453