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.test_decorators import test_tracker_info
30from acts.utils import force_airplane_mode
31
32WifiEnums = wutils.WifiEnums
33
34DEFAULT_TIMEOUT = 10
35GLOBAL_RE = 0
36BOINGO = 1
37UNKNOWN_FQDN = "@#@@!00fffffx"
38
39class WifiPasspointTest(acts.base_test.BaseTestClass):
40    """Tests for APIs in Android's WifiManager class.
41
42    Test Bed Requirement:
43    * One Android device
44    * Several Wi-Fi networks visible to the device, including an open Wi-Fi
45      network.
46    """
47
48    def setup_class(self):
49        self.dut = self.android_devices[0]
50        wutils.wifi_test_device_init(self.dut)
51        req_params = ("passpoint_networks",)
52        self.unpack_userparams(req_params)
53        asserts.assert_true(
54            len(self.passpoint_networks) > 0,
55            "Need at least one Passpoint network.")
56        wutils.wifi_toggle_state(self.dut, True)
57        self.unknown_fqdn = UNKNOWN_FQDN
58
59
60    def setup_test(self):
61        self.dut.droid.wakeLockAcquireBright()
62        self.dut.droid.wakeUpNow()
63
64
65    def teardown_test(self):
66        self.dut.droid.wakeLockRelease()
67        self.dut.droid.goToSleepNow()
68        wutils.reset_wifi(self.dut)
69
70
71    def on_fail(self, test_name, begin_time):
72        self.dut.take_bug_report(test_name, begin_time)
73
74
75    """Helper Functions"""
76
77
78    def install_passpoint_profile(self, passpoint_config):
79        """Install the Passpoint network Profile.
80
81        Args:
82            passpoint_config: A JSON dict of the Passpoint configuration.
83
84        """
85        asserts.assert_true(WifiEnums.SSID_KEY in passpoint_config,
86                "Key '%s' must be present in network definition." %
87                WifiEnums.SSID_KEY)
88        # Install the Passpoint profile.
89        self.dut.droid.addUpdatePasspointConfig(passpoint_config)
90
91
92    def check_passpoint_connection(self, passpoint_network):
93        """Verify the device is automatically able to connect to the Passpoint
94           network.
95
96           Args:
97               passpoint_network: SSID of the Passpoint network.
98
99        """
100        ad = self.dut
101        ad.ed.clear_all_events()
102        wutils.start_wifi_connection_scan(ad)
103        scan_results = ad.droid.wifiGetScanResults()
104        # Wait for scan to complete.
105        time.sleep(5)
106        ssid = passpoint_network
107        wutils.assert_network_in_list({WifiEnums.SSID_KEY: ssid}, scan_results)
108        # Passpoint network takes longer time to connect than normal networks.
109        # Every try comes with a timeout of 30s. Setting total timeout to 120s.
110        wutils.wifi_passpoint_connect(self.dut, passpoint_network, num_of_tries=4)
111        # Re-verify we are connected to the correct network.
112        network_info = self.dut.droid.wifiGetConnectionInfo()
113        if network_info[WifiEnums.SSID_KEY] != passpoint_network:
114            raise signals.TestFailure("Device did not connect to the passpoint"
115                                      " network.")
116
117
118    def get_configured_passpoint_and_delete(self):
119        """Get configured Passpoint network and delete using its FQDN."""
120        passpoint_config = self.dut.droid.getPasspointConfigs()
121        if not len(passpoint_config):
122            raise signals.TestFailure("Failed to fetch the list of configured"
123                                      "passpoint networks.")
124        if not wutils.delete_passpoint(self.dut, passpoint_config[0]):
125            raise signals.TestFailure("Failed to delete Passpoint configuration"
126                                      " with FQDN = %s" % passpoint_config[0])
127
128    """Tests"""
129
130    @test_tracker_info(uuid="b0bc0153-77bb-4594-8f19-cea2c6bd2f43")
131    def test_add_passpoint_network(self):
132        """Add a Passpoint network and verify device connects to it.
133
134        Steps:
135            1. Install a Passpoint Profile.
136            2. Verify the device connects to the required Passpoint SSID.
137            3. Get the Passpoint configuration added above.
138            4. Delete Passpoint configuration using its FQDN.
139            5. Verify that we are disconnected from the Passpoint network.
140
141        """
142        passpoint_config = self.passpoint_networks[BOINGO]
143        self.install_passpoint_profile(passpoint_config)
144        ssid = passpoint_config[WifiEnums.SSID_KEY]
145        self.check_passpoint_connection(ssid)
146        self.get_configured_passpoint_and_delete()
147        wutils.wait_for_disconnect(self.dut)
148
149
150    @test_tracker_info(uuid="eb29d6e2-a755-4c9c-9e4e-63ea2277a64a")
151    def test_update_passpoint_network(self):
152        """Update a previous Passpoint network and verify device still connects
153           to it.
154
155        1. Install a Passpoint Profile.
156        2. Verify the device connects to the required Passpoint SSID.
157        3. Update the Passpoint Profile.
158        4. Verify device is still connected to the Passpoint SSID.
159        5. Get the Passpoint configuration added above.
160        6. Delete Passpoint configuration using its FQDN.
161
162        """
163        passpoint_config = self.passpoint_networks[BOINGO]
164        self.install_passpoint_profile(passpoint_config)
165        ssid = passpoint_config[WifiEnums.SSID_KEY]
166        self.check_passpoint_connection(ssid)
167
168        # Update passpoint configuration using the original profile because we
169        # do not have real profile with updated credentials to use.
170        self.install_passpoint_profile(passpoint_config)
171
172        # Wait for a Disconnect event from the supplicant.
173        wutils.wait_for_disconnect(self.dut)
174
175        # Now check if we are again connected with the updated profile.
176        self.check_passpoint_connection(ssid)
177
178        self.get_configured_passpoint_and_delete()
179        wutils.wait_for_disconnect(self.dut)
180
181
182    @test_tracker_info(uuid="b6e8068d-faa1-49f2-b421-c60defaed5f0")
183    def test_add_delete_list_of_passpoint_network(self):
184        """Add multiple passpoint networks, list them and delete one by one.
185
186        1. Install Passpoint Profile A.
187        2. Install Passpoint Profile B.
188        3. Get all the Passpoint configurations added above and verify.
189        6. Ensure all Passpoint configurations can be deleted.
190
191        """
192        for passpoint_config in self.passpoint_networks:
193            self.install_passpoint_profile(passpoint_config)
194            time.sleep(DEFAULT_TIMEOUT)
195        configs = self.dut.droid.getPasspointConfigs()
196        if not len(configs) or len(configs) != len(self.passpoint_networks):
197            raise signals.TestFailure("Failed to fetch some or all of the"
198                                      " configured passpoint networks.")
199        for config in configs:
200            if not wutils.delete_passpoint(self.dut, config):
201                raise signals.TestFailure("Failed to delete Passpoint"
202                                          " configuration with FQDN = %s" %
203                                          config)
204
205
206    @test_tracker_info(uuid="a53251be-7aaf-41fc-a5f3-63984269d224")
207    def test_delete_unknown_fqdn(self):
208        """Negative test to delete Passpoint profile using an unknown FQDN.
209
210        1. Pass an unknown FQDN for removal.
211        2. Verify that it was not successful.
212
213        """
214        if wutils.delete_passpoint(self.dut, self.unknown_fqdn):
215            raise signals.TestFailure("Failed because an unknown FQDN"
216                                      " was successfully deleted.")
217
218
219    @test_tracker_info(uuid="bf03c03a-e649-4e2b-a557-1f791bd98951")
220    def test_passpoint_failover(self):
221        """Add a pair of passpoint networks and test failover when one of the"
222           profiles is removed.
223
224        1. Install a Passpoint Profile A and B.
225        2. Verify device connects to a Passpoint network and get SSID.
226        3. Delete the current Passpoint profile using its FQDN.
227        4. Verify device fails over and connects to the other Passpoint SSID.
228        5. Delete Passpoint configuration using its FQDN.
229
230        """
231        # Install both Passpoint profiles on the device.
232        passpoint_ssid = list()
233        for passpoint_config in self.passpoint_networks:
234            passpoint_ssid.append(passpoint_config[WifiEnums.SSID_KEY])
235            self.install_passpoint_profile(passpoint_config)
236            time.sleep(DEFAULT_TIMEOUT)
237
238        # Get the current network and the failover network.
239        wutils.wait_for_connect(self.dut)
240        current_passpoint = self.dut.droid.wifiGetConnectionInfo()
241        current_ssid = current_passpoint[WifiEnums.SSID_KEY]
242        if current_ssid not in passpoint_ssid:
243           raise signals.TestFailure("Device did not connect to any of the "
244                                     "configured Passpoint networks.")
245
246        expected_ssid =  self.passpoint_networks[0][WifiEnums.SSID_KEY]
247        if current_ssid == expected_ssid:
248            expected_ssid = self.passpoint_networks[1][WifiEnums.SSID_KEY]
249
250        # Remove the current Passpoint profile.
251        for network in self.passpoint_networks:
252            if network[WifiEnums.SSID_KEY] == current_ssid:
253                if not wutils.delete_passpoint(self.dut, network["fqdn"]):
254                    raise signals.TestFailure("Failed to delete Passpoint"
255                                              " configuration with FQDN = %s" %
256                                              network["fqdn"])
257        # Verify device fails over and connects to the other passpoint network.
258        time.sleep(DEFAULT_TIMEOUT)
259
260        current_passpoint = self.dut.droid.wifiGetConnectionInfo()
261        if current_passpoint[WifiEnums.SSID_KEY] != expected_ssid:
262            raise signals.TestFailure("Device did not failover to the %s"
263                                      " passpoint network" % expected_ssid)
264
265        # Delete the remaining Passpoint profile.
266        self.get_configured_passpoint_and_delete()
267        wutils.wait_for_disconnect(self.dut)
268