• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3.4
2#
3#   Copyright 2018 - 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.signals as signals
24import acts.test_utils.wifi.wifi_test_utils as wutils
25import acts.utils
26
27from acts import asserts
28from acts.controllers.android_device import SL4A_APK_NAME
29from acts.test_decorators import test_tracker_info
30from acts.test_utils.wifi.WifiBaseTest import WifiBaseTest
31from acts.test_utils.wifi import wifi_constants
32
33WifiEnums = wutils.WifiEnums
34
35# Network request timeout to use.
36NETWORK_REQUEST_TIMEOUT_MS = 60 * 1000
37# Timeout to wait for instant failure.
38NETWORK_REQUEST_INSTANT_FAILURE_TIMEOUT_SEC = 5
39
40class WifiNetworkRequestTest(WifiBaseTest):
41    """Tests for NetworkRequest with WifiNetworkSpecifier API surface.
42
43    Test Bed Requirement:
44    * one Android device
45    * Several Wi-Fi networks visible to the device, including an open Wi-Fi
46      network.
47    """
48
49    def __init__(self, controllers):
50        WifiBaseTest.__init__(self, controllers)
51
52    def setup_class(self):
53        self.dut = self.android_devices[0]
54        wutils.wifi_test_device_init(self.dut)
55        req_params = []
56        opt_param = [
57            "open_network", "reference_networks"
58        ]
59        self.unpack_userparams(
60            req_param_names=req_params, opt_param_names=opt_param)
61
62        if "AccessPoint" in self.user_params:
63            self.legacy_configure_ap_and_start(wpa_network=True,
64                                               wep_network=True)
65
66        asserts.assert_true(
67            len(self.reference_networks) > 0,
68            "Need at least one reference network with psk.")
69        self.wpa_psk_2g = self.reference_networks[0]["2g"]
70        self.wpa_psk_5g = self.reference_networks[0]["5g"]
71        self.open_2g = self.open_network[0]["2g"]
72        self.open_5g = self.open_network[0]["5g"]
73
74    def setup_test(self):
75        self.dut.droid.wakeLockAcquireBright()
76        self.dut.droid.wakeUpNow()
77        self.remove_approvals()
78        self.clear_deleted_ephemeral_networks()
79        wutils.wifi_toggle_state(self.dut, True)
80        self.dut.ed.clear_all_events()
81
82    def teardown_test(self):
83        self.dut.droid.wakeLockRelease()
84        self.dut.droid.goToSleepNow()
85        self.dut.droid.wifiReleaseNetworkAll()
86        self.dut.droid.wifiDisconnect()
87        wutils.reset_wifi(self.dut)
88        self.dut.ed.clear_all_events()
89
90    def on_fail(self, test_name, begin_time):
91        self.dut.take_bug_report(test_name, begin_time)
92        self.dut.cat_adb_log(test_name, begin_time)
93
94    def teardown_class(self):
95        if "AccessPoint" in self.user_params:
96            del self.user_params["reference_networks"]
97            del self.user_params["open_network"]
98
99    """Helper Functions"""
100    def wait_for_network_lost(self):
101        """
102        Wait for network lost callback from connectivity service (wifi
103        disconnect).
104
105        Args:
106            ad: Android device object.
107        """
108        try:
109            self.dut.droid.wifiStartTrackingStateChange()
110            event = self.dut.ed.pop_event(
111                wifi_constants.WIFI_NETWORK_CB_ON_LOST, 10)
112            self.dut.droid.wifiStopTrackingStateChange()
113        except queue.Empty:
114            raise signals.TestFailure(
115                "Device did not disconnect from the network")
116
117    def remove_approvals(self):
118        self.dut.log.debug("Removing all approvals from sl4a app")
119        self.dut.adb.shell(
120            "cmd wifi network-requests-remove-user-approved-access-points"
121            + " " + SL4A_APK_NAME)
122
123    def clear_deleted_ephemeral_networks(self):
124        self.dut.log.debug("Clearing deleted ephemeral networks")
125        self.dut.adb.shell(
126            "cmd wifi clear-deleted-ephemeral-networks")
127
128    @test_tracker_info(uuid="d70c8380-61ba-48a3-b76c-a0b55ce4eabf")
129    def test_connect_to_wpa_psk_2g_with_ssid(self):
130        """
131        Initiates a connection to network via network request with specific SSID
132
133        Steps:
134        1. Send a network specifier with the specific SSID/credentials of
135           WPA-PSK 2G network.
136        2. Wait for platform to scan and find matching networks.
137        3. Simulate user selecting the network.
138        4. Ensure that the device connects to the network.
139        """
140        wutils.wifi_connect_using_network_request(self.dut, self.wpa_psk_2g,
141                                                  self.wpa_psk_2g)
142
143    @test_tracker_info(uuid="44f2bf40-a282-4413-b8f2-3abb3caa49ee")
144    def test_connect_to_open_5g_with_ssid(self):
145        """
146        Initiates a connection to network via network request with specific SSID
147
148        Steps:
149        1. Send a network specifier with the specific SSID of Open 5G network.
150        2. Wait for platform to scan and find matching networks.
151        3. Simulate user selecting the network.
152        4. Ensure that the device connects to the network.
153        """
154        wutils.wifi_connect_using_network_request(self.dut, self.open_5g,
155                                                  self.open_5g)
156
157    @test_tracker_info(uuid="09d1823e-4f85-42f8-8c20-de7637f6d4be")
158    def test_connect_to_wpa_psk_5g_with_ssid_pattern(self):
159        """
160        Initiates a connection to network via network request with SSID pattern
161
162        Steps:
163        1. Send a network specifier with the SSID pattern/credentials of
164           WPA-PSK 5G network.
165        2. Wait for platform to scan and find matching networks.
166        3. Simulate user selecting the network.
167        4. Ensure that the device connects to the network.
168        """
169        network_specifier = self.wpa_psk_5g.copy();
170        # Remove ssid & replace with ssid pattern.
171        network_ssid = network_specifier.pop(WifiEnums.SSID_KEY)
172        # Remove the last element of ssid & replace with .* to create a matching
173        # pattern.
174        network_specifier[WifiEnums.SSID_PATTERN_KEY] = network_ssid[:-1] + ".*"
175        wutils.wifi_connect_using_network_request(self.dut, self.wpa_psk_5g,
176                                                  network_specifier)
177
178    @test_tracker_info(uuid="52216329-06f1-45ef-8d5f-de8b02d9f975")
179    def test_connect_to_open_5g_after_connecting_to_wpa_psk_2g(self):
180        """
181        Initiates a connection to network via network request with SSID pattern
182
183        Steps:
184        1. Send a network specifier with the specific SSID of Open 5G network.
185        2. Wait for platform to scan and find matching networks.
186        3. Simulate user selecting the network.
187        4. Ensure that the device connects to the network.
188        5. Release the network request.
189        6. Send another network specifier with the specific SSID & credentials
190           of WPA-PSK 2G network.
191        7. Ensure we disconnect from the previous network.
192        8. Wait for platform to scan and find matching networks.
193        9. Simulate user selecting the new network.
194        10. Ensure that the device connects to the new network.
195        """
196        # Complete flow for the first request.
197        wutils.wifi_connect_using_network_request(self.dut, self.wpa_psk_2g,
198                                                  self.wpa_psk_2g)
199        # Release the request.
200        self.dut.droid.wifiReleaseNetwork(self.wpa_psk_2g)
201        # Ensure we disconnected from the previous network.
202        wutils.wait_for_disconnect(self.dut)
203        self.dut.log.info("Disconnected from network %s", self.wpa_psk_2g)
204        # Complete flow for the second request.
205        wutils.wifi_connect_using_network_request(self.dut, self.open_5g,
206                                                  self.open_5g)
207
208    @test_tracker_info(uuid="f28b5dc9-771f-42ef-8178-e55e9a16f5c7")
209    def test_connect_to_wpa_psk_5g_while_connecting_to_open_2g(self):
210        """
211        Initiates a connection to network via network request with specific SSID
212
213        Steps:
214        1. Send a network specifier with the specific SSID & credentials of
215           WPA-PSK 5G network.
216        2. Send another network specifier with the specific SSID of Open 2G
217           network.
218        3. Ensure we disconnect from the previous network.
219        4. Wait for platform to scan and find matching networks.
220        5. Simulate user selecting the new network.
221        6. Ensure that the device connects to the new network.
222        """
223        # Make the first request.
224        self.dut.droid.wifiRequestNetworkWithSpecifier(self.open_2g)
225        self.dut.log.info("Sent network request with %s", self.open_2g)
226        # Complete flow for the second request.
227        wutils.wifi_connect_using_network_request(self.dut, self.wpa_psk_5g,
228                                                  self.wpa_psk_5g)
229
230    @test_tracker_info(uuid="2ab82a98-37da-4b27-abb6-578bedebccdc")
231    def test_connect_to_open_5g_while_connected_to_wpa_psk_2g(self):
232        """
233        Initiates a connection to network via network request with specific SSID
234
235        Steps:
236        1. Send a network specifier with the specific SSID of Open 5G network.
237        2. Wait for platform to scan and find matching networks.
238        3. Simulate user selecting the network.
239        4. Ensure that the device connects to the network.
240        5. Send another network specifier with the specific SSID & credentials
241           of WPA-PSK 2G network.
242        6. Ensure we disconnect from the previous network.
243        7. Wait for platform to scan and find matching networks.
244        8. Simulate user selecting the new network.
245        9. Ensure that the device connects to the new network.
246        """
247        # Complete flow for the first request.
248        wutils.wifi_connect_using_network_request(self.dut, self.wpa_psk_2g,
249                                                  self.wpa_psk_2g)
250        # Send the second request.
251        self.dut.droid.wifiRequestNetworkWithSpecifier(self.open_5g)
252        self.dut.log.info("Sent network request with %s", self.open_5g)
253        # Ensure we do not disconnect from the previous network until the user
254        # approves the new request.
255        self.dut.ed.clear_all_events()
256        wutils.ensure_no_disconnect(self.dut)
257
258        # Now complete the flow and ensure we connected to second request.
259        wutils.wait_for_wifi_connect_after_network_request(self.dut,
260                                                           self.open_5g)
261
262    @test_tracker_info(uuid="f0bb2213-b3d1-4fb8-bbdc-ad55c4fb05ed")
263    def test_connect_to_wpa_psk_2g_which_is_already_approved(self):
264        """
265        Initiates a connection to network via network request with specific SSID
266        bypassing user approval.
267
268        Steps:
269        1. Send a network specifier with the specific SSID/credentials of
270           WPA-PSK 2G network.
271        2. Wait for platform to scan and find matching networks.
272        3. Simulate user selecting the network.
273        4. Ensure that the device connects to the network.
274        5. Ensure we disconnect from the previous network.
275        6. Send another network specifier with the specific
276           SSID/BSSID/credentials of WPA-PSK 2G network.
277        7. Ensure that the device bypasses user approval & connects to the
278           same network.
279        """
280        # Complete flow for the first request.
281        wutils.wifi_connect_using_network_request(self.dut, self.wpa_psk_2g,
282                                                  self.wpa_psk_2g)
283        # Release the request.
284        self.dut.droid.wifiReleaseNetwork(self.wpa_psk_2g)
285        # Ensure we disconnected from the network.
286        wutils.wait_for_disconnect(self.dut)
287        self.dut.log.info("Disconnected from network %s", self.wpa_psk_2g)
288        self.dut.ed.clear_all_events()
289
290        # Find bssid for the WPA-PSK 2G network.
291        scan_results = self.dut.droid.wifiGetScanResults()
292        match_results = wutils.match_networks(
293            {WifiEnums.SSID_KEY: self.wpa_psk_2g[WifiEnums.SSID_KEY]},
294            scan_results)
295        asserts.assert_equal(len(match_results), 1,
296                             "Cannot find bssid for WPA-PSK 2G network")
297        bssid = match_results[0][WifiEnums.BSSID_KEY]
298        # Send the second request with bssid.
299        network_specifier_with_bssid = self.wpa_psk_2g.copy();
300        network_specifier_with_bssid[WifiEnums.BSSID_KEY] = bssid
301        self.dut.droid.wifiRequestNetworkWithSpecifier(
302            network_specifier_with_bssid)
303        self.dut.log.info("Sent network request with %r",
304                          network_specifier_with_bssid)
305
306        # Ensure we connected to second request without user approval.
307        wutils.wait_for_connect(self.dut, self.wpa_psk_2g[WifiEnums.SSID_KEY])
308
309    @test_tracker_info(uuid="fcf84d94-5f6e-4bd6-9f76-40a0228d4ebe")
310    def test_connect_to_wpa_psk_2g_which_is_already_approved_but_then_forgot(self):
311        """
312        Initiates a connection to network via network request with specific SSID
313        with user approval.
314
315        Steps:
316        1. Send a network specifier with the specific SSID/credentials of
317           WPA-PSK 2G network.
318        2. Wait for platform to scan and find matching networks.
319        3. Simulate user selecting the network.
320        4. Ensure that the device connects to the network.
321        4. Simulate user fogetting the network from the UI.
322        6. Ensure we disconnect from the previous network.
323        7. Send another network specifier with the specific
324           SSID/BSSID/credentials of WPA-PSK 2G network.
325        8. Ensure that the device does not bypass user approval & connects to the
326           same network with user approval. (This should also clear the blacklist)
327        9. Send the same network specifier with the specific
328           SSID/BSSID/credentials of WPA-PSK 2G network.
329        10.Ensure that the device bypasses user approval now & connects to the
330           same network.
331        """
332        # Complete flow for the first request.
333        wutils.wifi_connect_using_network_request(self.dut, self.wpa_psk_2g,
334                                                  self.wpa_psk_2g)
335
336        # Simulate user forgeting the ephemeral network.
337        self.dut.droid.wifiDisableEphemeralNetwork(
338            self.wpa_psk_2g[WifiEnums.SSID_KEY])
339        # Ensure we disconnected from the network.
340        wutils.wait_for_disconnect(self.dut)
341        self.dut.log.info("Disconnected from network %s", self.wpa_psk_2g)
342        self.dut.ed.clear_all_events()
343        # Release the first request.
344        self.dut.droid.wifiReleaseNetwork(self.wpa_psk_2g)
345
346        # Find bssid for the WPA-PSK 2G network.
347        scan_results = self.dut.droid.wifiGetScanResults()
348        match_results = wutils.match_networks(
349            {WifiEnums.SSID_KEY: self.wpa_psk_2g[WifiEnums.SSID_KEY]},
350            scan_results)
351        asserts.assert_equal(len(match_results), 1,
352                             "Cannot find bssid for WPA-PSK 2G network")
353        bssid = match_results[0][WifiEnums.BSSID_KEY]
354        # Send the second request with bssid.
355        network_specifier_with_bssid = self.wpa_psk_2g.copy();
356        network_specifier_with_bssid[WifiEnums.BSSID_KEY] = bssid
357        self.dut.droid.wifiRequestNetworkWithSpecifier(
358            network_specifier_with_bssid)
359        self.dut.log.info("Sent network request with %r",
360                          network_specifier_with_bssid)
361
362        # Ensure that we did not connect bypassing user approval.
363        assert_msg = "Device should not connect without user approval"
364        asserts.assert_false(
365            wutils.wait_for_connect(self.dut,
366                                    self.wpa_psk_2g[WifiEnums.SSID_KEY],
367                                    assert_on_fail=False),
368            assert_msg)
369
370        # Now complete the flow and ensure we connected to second request.
371        wutils.wait_for_wifi_connect_after_network_request(self.dut,
372                                                           self.wpa_psk_2g)
373
374        # Now make the same request again & ensure that we connect without user
375        # approval.
376        self.dut.droid.wifiRequestNetworkWithSpecifier(
377            network_specifier_with_bssid)
378        self.dut.log.info("Sent network request with %r",
379                          network_specifier_with_bssid)
380        wutils.wait_for_connect(self.dut, self.wpa_psk_2g[WifiEnums.SSID_KEY])
381
382    @test_tracker_info(uuid="2f90a266-f04d-4932-bb5b-d075bedfd56d")
383    def test_match_failure_with_invalid_ssid_pattern(self):
384        """
385        Initiates a connection to network via network request with SSID pattern
386        that does not match any networks.
387
388        Steps:
389        1. Send a network specifier with the non-matching SSID pattern.
390        2. Ensure that the platform does not retrun any matching networks.
391        3. Wait for the request to timeout.
392        """
393        network = self.wpa_psk_5g
394        network_specifier = self.wpa_psk_5g.copy();
395        # Remove ssid & replace with invalid ssid pattern.
396        network_ssid = network_specifier.pop(WifiEnums.SSID_KEY)
397        network_specifier[WifiEnums.SSID_PATTERN_KEY] = \
398            network_ssid + "blah" + ".*"
399
400        self.dut.droid.wifiStartTrackingStateChange()
401        expected_ssid = network[WifiEnums.SSID_KEY]
402
403        self.dut.droid.wifiRequestNetworkWithSpecifierWithTimeout(
404              network_specifier, NETWORK_REQUEST_TIMEOUT_MS)
405        self.dut.log.info("Sent network request with invalid specifier %s",
406                    network_specifier)
407        time.sleep(wifi_constants.NETWORK_REQUEST_CB_REGISTER_DELAY_SEC)
408        self.dut.droid.wifiRegisterNetworkRequestMatchCallback()
409        # Wait for the request to timeout. In the meantime, platform will scan
410        # and return matching networks. Ensure the matching networks list is
411        # empty.
412        start_time = time.time()
413        has_request_timedout = False
414        try:
415          while not has_request_timedout and time.time() - start_time <= \
416              NETWORK_REQUEST_TIMEOUT_MS / 1000:
417                # Pop all network request related events.
418                network_request_events = \
419                    self.dut.ed.pop_events("WifiManagerNetwork.*", 30)
420                asserts.assert_true(network_request_events, "invalid events")
421                for network_request_event in network_request_events:
422                    # Handle the network match callbacks.
423                    if network_request_event["name"] == \
424                        wifi_constants.WIFI_NETWORK_REQUEST_MATCH_CB_ON_MATCH:
425                        matched_scan_results = network_request_event["data"]
426                        self.dut.log.debug(
427                            "Network request on match results %s",
428                            matched_scan_results)
429                        asserts.assert_false(matched_scan_results,
430                                             "Empty network matches expected")
431                    # Handle the network request unavailable timeout.
432                    if network_request_event["name"] == \
433                        wifi_constants.WIFI_NETWORK_CB_ON_UNAVAILABLE:
434                        self.dut.log.info("Network request timed out")
435                        has_request_timedout = True
436        except queue.Empty:
437            asserts.fail("No events returned")
438        finally:
439            self.dut.droid.wifiStopTrackingStateChange()
440        asserts.assert_true(has_request_timedout,
441                            "Network request did not timeout")
442
443    @test_tracker_info(uuid="760c3768-697d-442b-8d61-cfe02f10ceff")
444    def test_connect_failure_user_rejected(self):
445        """
446        Initiates a connection to network via network request with specific SSID
447        which the user rejected.
448
449        Steps:
450        1. Send a network specifier with the specific SSID/credentials of
451           WPA-PSK 5G network.
452        2. Wait for platform to scan and find matching networks.
453        3. Simulate user rejecting the network.
454        4. Ensure that we get an instant onUnavailable callback.
455        5. Simulate user fogetting the network from the UI.
456        """
457        network = self.wpa_psk_5g
458        expected_ssid = network[WifiEnums.SSID_KEY]
459
460        self.dut.droid.wifiStartTrackingStateChange()
461
462        self.dut.droid.wifiRequestNetworkWithSpecifierWithTimeout(
463              network, NETWORK_REQUEST_TIMEOUT_MS)
464        self.dut.log.info("Sent network request with specifier %s", network)
465        time.sleep(wifi_constants.NETWORK_REQUEST_CB_REGISTER_DELAY_SEC)
466        self.dut.droid.wifiRegisterNetworkRequestMatchCallback()
467
468        # Wait for the platform to scan and return a list of networks
469        # matching the request
470        try:
471            matched_network = None
472            for _ in [0,  3]:
473                on_match_event = self.dut.ed.pop_event(
474                    wifi_constants.WIFI_NETWORK_REQUEST_MATCH_CB_ON_MATCH, 30)
475                asserts.assert_true(on_match_event,
476                                    "Network request on match not received.")
477                matched_scan_results = on_match_event["data"]
478                self.dut.log.debug("Network request on match results %s",
479                                   matched_scan_results)
480                matched_network = wutils.match_networks(
481                    {WifiEnums.SSID_KEY: network[WifiEnums.SSID_KEY]},
482                     matched_scan_results)
483                if matched_network:
484                    break;
485            asserts.assert_true(
486                matched_network, "Target network %s not found" % network)
487
488            # Send user rejection.
489            self.dut.droid.wifiSendUserRejectionForNetworkRequestMatch()
490            self.dut.log.info("Sent user rejection for network request %s",
491                              expected_ssid)
492
493            # Wait for the platform to raise unavailable callback
494            # instantaneously.
495            on_unavailable_event = self.dut.ed.pop_event(
496                wifi_constants.WIFI_NETWORK_CB_ON_UNAVAILABLE,
497                NETWORK_REQUEST_INSTANT_FAILURE_TIMEOUT_SEC)
498            asserts.assert_true(on_unavailable_event,
499                                "Network request on available not received.")
500        except queue.Empty:
501            asserts.fail("Expected events not returned")
502        finally:
503            self.dut.droid.wifiStopTrackingStateChange()
504