blob: 6bbeb5e623a48c8f3f1d5a9979a5baa4427c5166 [file] [log] [blame]
#!/usr/bin/env python3.4
#
# Copyright 2018 - The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import queue
import time
from acts import asserts
from acts.controllers.android_device import SL4A_APK_NAME
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
from acts_contrib.test_utils.net import connectivity_const as cconsts
from acts_contrib.test_utils.wifi import wifi_constants
import acts_contrib.test_utils.wifi.wifi_test_utils as wutils
from acts_contrib.test_utils.wifi.aware import aware_test_utils as autils
WifiEnums = wutils.WifiEnums
# Network request timeout to use.
NETWORK_REQUEST_TIMEOUT_MS = 60 * 1000
# Timeout to wait for instant failure.
NETWORK_REQUEST_INSTANT_FAILURE_TIMEOUT_SEC = 5
class WifiNetworkRequestTest(WifiBaseTest):
"""Tests for NetworkRequest with WifiNetworkSpecifier API surface.
Test Bed Requirement:
* one Android device
* Several Wi-Fi networks visible to the device, including an open Wi-Fi
network.
"""
def __init__(self, configs):
super().__init__(configs)
self.enable_packet_log = True
def setup_class(self):
super().setup_class()
self.dut = self.android_devices[0]
wutils.wifi_test_device_init(self.dut)
req_params = []
opt_param = [
"open_network", "reference_networks", "sta_concurrency_supported_models"
]
self.unpack_userparams(
req_param_names=req_params, opt_param_names=opt_param)
if "AccessPoint" in self.user_params:
self.legacy_configure_ap_and_start(wpa_network=True,
wep_network=True)
elif "OpenWrtAP" in self.user_params:
self.openwrt = self.access_points[0]
self.configure_openwrt_ap_and_start(open_network=True,
wpa_network=True,
wep_network=self.openwrt.is_version_under_20())
asserts.assert_true(
len(self.reference_networks) > 0,
"Need at least one reference network with psk.")
self.wpa_psk_2g = self.reference_networks[0]["2g"]
self.wpa_psk_5g = self.reference_networks[0]["5g"]
self.open_2g = self.open_network[0]["2g"]
self.open_5g = self.open_network[0]["5g"]
if "sta_concurrency_supported_models" in self.user_params:
self.sta_concurrency_supported_models = \
self.dut.model in self.sta_concurrency_supported_models
else:
self.sta_concurrency_supported_models = False
def setup_test(self):
super().setup_test()
self.dut.droid.wakeLockAcquireBright()
self.dut.droid.wakeUpNow()
self.remove_approvals()
self.clear_user_disabled_networks()
wutils.wifi_toggle_state(self.dut, True)
self.dut.ed.clear_all_events()
def teardown_test(self):
super().teardown_test()
self.dut.droid.wakeLockRelease()
self.dut.droid.goToSleepNow()
self.dut.droid.wifiDisconnect()
wutils.reset_wifi(self.dut)
wutils.wifi_toggle_state(self.dut, False)
self.dut.ed.clear_all_events()
def teardown_class(self):
if "AccessPoint" in self.user_params:
del self.user_params["reference_networks"]
del self.user_params["open_network"]
"""Helper Functions"""
def remove_approvals(self):
self.dut.log.debug("Removing all approvals from sl4a app")
self.dut.adb.shell(
"cmd wifi network-requests-remove-user-approved-access-points"
+ " " + SL4A_APK_NAME)
def clear_user_disabled_networks(self):
self.dut.log.debug("Clearing user disabled networks")
self.dut.adb.shell(
"cmd wifi clear-user-disabled-networks")
@test_tracker_info(uuid="d70c8380-61ba-48a3-b76c-a0b55ce4eabf")
def test_connect_to_wpa_psk_2g_with_ssid(self):
"""
Initiates a connection to network via network request with specific SSID
Steps:
1. Send a network specifier with the specific SSID/credentials of
WPA-PSK 2G network.
2. Wait for platform to scan and find matching networks.
3. Simulate user selecting the network.
4. Ensure that the device connects to the network.
"""
wutils.wifi_connect_using_network_request(self.dut, self.wpa_psk_2g,
self.wpa_psk_2g)
@test_tracker_info(uuid="44f2bf40-a282-4413-b8f2-3abb3caa49ee")
def test_connect_to_open_5g_with_ssid(self):
"""
Initiates a connection to network via network request with specific SSID
Steps:
1. Send a network specifier with the specific SSID of Open 5G network.
2. Wait for platform to scan and find matching networks.
3. Simulate user selecting the network.
4. Ensure that the device connects to the network.
"""
wutils.wifi_connect_using_network_request(self.dut, self.open_5g,
self.open_5g)
@test_tracker_info(uuid="09d1823e-4f85-42f8-8c20-de7637f6d4be")
def test_connect_to_wpa_psk_5g_with_ssid_pattern(self):
"""
Initiates a connection to network via network request with SSID pattern
Steps:
1. Send a network specifier with the SSID pattern/credentials of
WPA-PSK 5G network.
2. Wait for platform to scan and find matching networks.
3. Simulate user selecting the network.
4. Ensure that the device connects to the network.
"""
network_specifier = self.wpa_psk_5g.copy();
# Remove ssid & replace with ssid pattern.
network_ssid = network_specifier.pop(WifiEnums.SSID_KEY)
# Remove the last element of ssid & replace with .* to create a matching
# pattern.
network_specifier[WifiEnums.SSID_PATTERN_KEY] = network_ssid[:-1] + ".*"
wutils.wifi_connect_using_network_request(self.dut, self.wpa_psk_5g,
network_specifier)
@test_tracker_info(uuid="52216329-06f1-45ef-8d5f-de8b02d9f975")
def test_connect_to_open_5g_after_connecting_to_wpa_psk_2g(self):
"""
Initiates a connection to network via network request with SSID pattern
Steps:
1. Send a network specifier with the specific SSID of Open 5G network.
2. Wait for platform to scan and find matching networks.
3. Simulate user selecting the network.
4. Ensure that the device connects to the network.
5. Release the network request.
6. Send another network specifier with the specific SSID & credentials
of WPA-PSK 2G network.
7. Ensure we disconnect from the previous network.
8. Wait for platform to scan and find matching networks.
9. Simulate user selecting the new network.
10. Ensure that the device connects to the new network.
"""
# Complete flow for the first request.
key = wutils.wifi_connect_using_network_request(self.dut,
self.wpa_psk_2g,
self.wpa_psk_2g)
# Release the request.
self.dut.log.info("Released network request %s", self.wpa_psk_2g)
self.dut.droid.connectivityUnregisterNetworkCallback(key)
# Ensure we disconnected from the network.
time.sleep(10)
self.dut.ed.clear_all_events()
# Complete flow for the second request.
wutils.wifi_connect_using_network_request(self.dut, self.open_5g,
self.open_5g)
@test_tracker_info(uuid="f28b5dc9-771f-42ef-8178-e55e9a16f5c7")
def test_connect_to_wpa_psk_5g_while_connecting_to_open_2g(self):
"""
Initiates a connection to network via network request with specific SSID
Steps:
1. Send a network specifier with the specific SSID & credentials of
WPA-PSK 5G network.
2. Send another network specifier with the specific SSID of Open 2G
network.
3. Ensure we disconnect from the previous network.
4. Wait for platform to scan and find matching networks.
5. Simulate user selecting the new network.
6. Ensure that the device connects to the new network.
"""
# Make the first request.
key = self.dut.droid.connectivityRequestWifiNetwork(self.open_2g, 0)
self.dut.log.info("Sent network request with %s ", self.open_2g)
# Complete flow for the second request.
wutils.wifi_connect_using_network_request(self.dut, self.wpa_psk_5g,
self.wpa_psk_5g)
@test_tracker_info(uuid="2ab82a98-37da-4b27-abb6-578bedebccdc")
def test_connect_to_open_5g_while_connected_to_wpa_psk_2g(self):
"""
Initiates a connection to network via network request with specific SSID
Steps:
1. Send a network specifier with the specific SSID of Open 5G network.
2. Wait for platform to scan and find matching networks.
3. Simulate user selecting the network.
4. Ensure that the device connects to the network.
5. Send another network specifier with the specific SSID & credentials
of WPA-PSK 2G network.
6. Ensure we disconnect from the previous network.
7. Wait for platform to scan and find matching networks.
8. Simulate user selecting the new network.
9. Ensure that the device connects to the new network.
"""
# Complete flow for the first request.
key1 = wutils.wifi_connect_using_network_request(self.dut,
self.wpa_psk_2g,
self.wpa_psk_2g)
# Send the second request.
key2 = self.dut.droid.connectivityRequestWifiNetwork(self.open_5g, 0)
self.dut.log.info("Sent network request with %s", self.open_5g)
self.dut.ed.clear_all_events()
# Ensure we do not disconnect from the previous network until the user
# approves the new request.
autils.fail_on_event_with_keys(
self.dut, cconsts.EVENT_NETWORK_CALLBACK,
60,
(cconsts.NETWORK_CB_KEY_ID, key1),
(cconsts.NETWORK_CB_KEY_EVENT, cconsts.NETWORK_CB_LOST))
# Now complete the flow and ensure we connected to second request.
wutils.wait_for_wifi_connect_after_network_request(self.dut,
self.open_5g,
key2)
@test_tracker_info(uuid="f0bb2213-b3d1-4fb8-bbdc-ad55c4fb05ed")
def test_connect_to_wpa_psk_2g_which_is_already_approved(self):
"""
Initiates a connection to network via network request with specific SSID
bypassing user approval.
Steps:
1. Send a network specifier with the specific SSID/credentials of
WPA-PSK 2G network.
2. Wait for platform to scan and find matching networks.
3. Simulate user selecting the network.
4. Ensure that the device connects to the network.
5. Ensure we disconnect from the previous network.
6. Send another network specifier with the specific
SSID/BSSID/credentials of WPA-PSK 2G network.
7. Ensure that the device bypasses user approval & connects to the
same network.
"""
# Complete flow for the first request.
key1 = wutils.wifi_connect_using_network_request(self.dut,
self.wpa_psk_2g,
self.wpa_psk_2g)
# Release the request.
self.dut.log.info("Released network request %s", self.wpa_psk_2g)
self.dut.droid.connectivityUnregisterNetworkCallback(key1)
# Ensure we disconnected from the network.
time.sleep(10)
self.dut.ed.clear_all_events()
# Find bssid for the WPA-PSK 2G network.
scan_results = self.dut.droid.wifiGetScanResults()
match_results = wutils.match_networks(
{WifiEnums.SSID_KEY: self.wpa_psk_2g[WifiEnums.SSID_KEY]},
scan_results)
asserts.assert_equal(len(match_results), 1,
"Cannot find bssid for WPA-PSK 2G network")
bssid = match_results[0][WifiEnums.BSSID_KEY]
# Send the second request with bssid.
network_specifier_with_bssid = self.wpa_psk_2g.copy();
network_specifier_with_bssid[WifiEnums.BSSID_KEY] = bssid
key2 = self.dut.droid.connectivityRequestWifiNetwork(
network_specifier_with_bssid, 0)
self.dut.log.info("Sent network request with %r",
network_specifier_with_bssid)
# Ensure we connected to second request without user approval.
autils.wait_for_event_with_keys(
self.dut, cconsts.EVENT_NETWORK_CALLBACK,
60,
(cconsts.NETWORK_CB_KEY_ID, key2),
(cconsts.NETWORK_CB_KEY_EVENT, cconsts.NETWORK_CB_AVAILABLE))
@test_tracker_info(uuid="fcf84d94-5f6e-4bd6-9f76-40a0228d4ebe")
def test_connect_to_wpa_psk_2g_which_is_already_approved_but_then_forgot(self):
"""
Initiates a connection to network via network request with specific SSID
with user approval.
Steps:
1. Send a network specifier with the specific SSID/credentials of
WPA-PSK 2G network.
2. Wait for platform to scan and find matching networks.
3. Simulate user selecting the network.
4. Ensure that the device connects to the network.
4. Simulate user fogetting the network from the UI.
6. Ensure we disconnect from the previous network.
7. Send another network specifier with the specific
SSID/BSSID/credentials of WPA-PSK 2G network.
8. Ensure that the device does not bypass user approval & connects to the
same network with user approval. (This should also clear the blacklist)
9. Send the same network specifier with the specific
SSID/BSSID/credentials of WPA-PSK 2G network.
10.Ensure that the device bypasses user approval now & connects to the
same network.
"""
# If the device supports STA + STA, user cannot trigger disconnect from UI.
# Skip the test in that case since the user disconnect causes a disconnect
# in the primary STA which will cause the test to fail.
if self.sta_concurrency_supported_models:
asserts.skip(
("Device %s supports STA + STA, skipping test.")
% self.dut.model)
# Complete flow for the first request.
key1 = wutils.wifi_connect_using_network_request(self.dut,
self.wpa_psk_2g,
self.wpa_psk_2g)
# Simulate user forgeting the ephemeral network.
self.dut.log.info("Triggered user disconnect from %s", self.wpa_psk_2g)
self.dut.droid.wifiUserDisconnectNetwork(self.wpa_psk_2g[WifiEnums.SSID_KEY])
# Ensure we disconnected from the network.
autils.wait_for_event_with_keys(
self.dut, cconsts.EVENT_NETWORK_CALLBACK,
60,
(cconsts.NETWORK_CB_KEY_ID, key1),
(cconsts.NETWORK_CB_KEY_EVENT, cconsts.NETWORK_CB_LOST))
self.dut.log.info("Disconnected from network %s", self.wpa_psk_2g)
self.dut.ed.clear_all_events()
# Release the first request.
self.dut.droid.connectivityUnregisterNetworkCallback(key1)
# Find bssid for the WPA-PSK 2G network.
scan_results = self.dut.droid.wifiGetScanResults()
match_results = wutils.match_networks(
{WifiEnums.SSID_KEY: self.wpa_psk_2g[WifiEnums.SSID_KEY]},
scan_results)
asserts.assert_equal(len(match_results), 1,
"Cannot find bssid for WPA-PSK 2G network")
bssid = match_results[0][WifiEnums.BSSID_KEY]
# Send the second request with bssid.
network_specifier_with_bssid = self.wpa_psk_2g.copy();
network_specifier_with_bssid[WifiEnums.BSSID_KEY] = bssid
key2 = self.dut.droid.connectivityRequestWifiNetwork(
network_specifier_with_bssid, 0)
self.dut.log.info("Sent network request with %r",
network_specifier_with_bssid)
# Ensure that we did not connect bypassing user approval.
autils.fail_on_event_with_keys(
self.dut, cconsts.EVENT_NETWORK_CALLBACK,
60,
(cconsts.NETWORK_CB_KEY_ID, key2),
(cconsts.NETWORK_CB_KEY_EVENT, cconsts.NETWORK_CB_AVAILABLE))
# Now complete the flow and ensure we connected to second request.
wutils.wait_for_wifi_connect_after_network_request(self.dut,
self.wpa_psk_2g,
key2)
# Now make the same request again & ensure that we connect without user
# approval.
key3 = self.dut.droid.connectivityRequestWifiNetwork(
network_specifier_with_bssid, 0)
self.dut.log.info("Sent network request with %r",
network_specifier_with_bssid)
autils.wait_for_event_with_keys(
self.dut, cconsts.EVENT_NETWORK_CALLBACK,
60,
(cconsts.NETWORK_CB_KEY_ID, key3),
(cconsts.NETWORK_CB_KEY_EVENT, cconsts.NETWORK_CB_AVAILABLE))
@test_tracker_info(uuid="2f90a266-f04d-4932-bb5b-d075bedfd56d")
def test_match_failure_with_invalid_ssid_pattern(self):
"""
Initiates a connection to network via network request with SSID pattern
that does not match any networks.
Steps:
1. Trigger a connect to one of the networks (as a saved network).
2. Send a network specifier with the non-matching SSID pattern.
3. Ensure that the platform does not return any matching networks.
4. Wait for the request to timeout.
"""
network = self.wpa_psk_5g
# Trigger a connection to a network as a saved network before the
# request and ensure that this does not change the behavior.
wutils.connect_to_wifi_network(self.dut, network, check_connectivity=False)
network_specifier = self.wpa_psk_5g.copy();
# Remove ssid & replace with invalid ssid pattern.
network_ssid = network_specifier.pop(WifiEnums.SSID_KEY)
network_specifier[WifiEnums.SSID_PATTERN_KEY] = \
network_ssid + "blah" + ".*"
key = self.dut.droid.connectivityRequestWifiNetwork(
network_specifier, NETWORK_REQUEST_TIMEOUT_MS)
self.dut.log.info("Sent network request with invalid specifier %s",
network_specifier)
time.sleep(wifi_constants.NETWORK_REQUEST_CB_REGISTER_DELAY_SEC)
self.dut.droid.wifiRegisterNetworkRequestMatchCallback()
# Wait for the request to timeout.
timeout_secs = NETWORK_REQUEST_TIMEOUT_MS * 2 / 1000
autils.wait_for_event_with_keys(
self.dut, cconsts.EVENT_NETWORK_CALLBACK,
timeout_secs,
(cconsts.NETWORK_CB_KEY_ID, key),
(cconsts.NETWORK_CB_KEY_EVENT, cconsts.NETWORK_CB_UNAVAILABLE))
@test_tracker_info(uuid="caa96f57-840e-4997-9280-655edd3b76ee")
def test_connect_failure_user_rejected(self):
"""
Initiates a connection to network via network request with specific SSID
which the user rejected.
Steps:
1. Send a network specifier with the specific SSID/credentials of
WPA-PSK 5G network.
2. Wait for platform to scan and find matching networks.
3. Simulate user rejecting the network.
4. Ensure that we get an instant onUnavailable callback.
5. Simulate user fogetting the network from the UI.
"""
network = self.wpa_psk_5g
expected_ssid = network[WifiEnums.SSID_KEY]
self.dut.droid.wifiStartTrackingStateChange()
key = self.dut.droid.connectivityRequestWifiNetwork(
network, NETWORK_REQUEST_TIMEOUT_MS)
self.dut.log.info("Sent network request with specifier %s", network)
time.sleep(wifi_constants.NETWORK_REQUEST_CB_REGISTER_DELAY_SEC)
self.dut.droid.wifiRegisterNetworkRequestMatchCallback()
# Wait for the platform to scan and return a list of networks
# matching the request
try:
matched_network = None
for _ in [0, 3]:
on_match_event = self.dut.ed.pop_event(
wifi_constants.WIFI_NETWORK_REQUEST_MATCH_CB_ON_MATCH, 30)
asserts.assert_true(on_match_event,
"Network request on match not received.")
matched_scan_results = on_match_event["data"]
self.dut.log.debug("Network request on match results %s",
matched_scan_results)
matched_network = wutils.match_networks(
{WifiEnums.SSID_KEY: network[WifiEnums.SSID_KEY]},
matched_scan_results)
if matched_network:
break;
asserts.assert_true(
matched_network, "Target network %s not found" % network)
# Send user rejection.
self.dut.droid.wifiSendUserRejectionForNetworkRequestMatch()
self.dut.log.info("Sent user rejection for network request %s",
expected_ssid)
# Wait for the platform to raise unavailable callback
# instantaneously.
autils.wait_for_event_with_keys(
self.dut, cconsts.EVENT_NETWORK_CALLBACK,
NETWORK_REQUEST_INSTANT_FAILURE_TIMEOUT_SEC,
(cconsts.NETWORK_CB_KEY_ID, key),
(cconsts.NETWORK_CB_KEY_EVENT, cconsts.NETWORK_CB_UNAVAILABLE))
except queue.Empty:
asserts.fail("Expected events not returned")
finally:
self.dut.droid.wifiStopTrackingStateChange()