blob: 062da8e48043c1f92a57f68c5ab9cb53695e25f1 [file] [log] [blame]
"""Tests for Bluetooth PAN profile functionalities."""
import contextlib
import time
from mobly import test_runner
from mobly import signals
from mobly.controllers.android_device_lib import jsonrpc_client_base
from blueberry.utils import blueberry_base_test
from blueberry.utils import bt_test_utils
# Timeout to wait for NAP service connection to be specific state in second.
CONNECTION_TIMEOUT_SECS = 20
# Interval time between ping requests in second.
PING_INTERVAL_TIME_SEC = 2
# Timeout to wait for ping success in second.
PING_TIMEOUT_SEC = 60
# A URL is used to verify internet by ping request.
TEST_URL = 'http://www.google.com'
# A string representing SIM State is ready.
SIM_STATE_READY = 'READY'
class BluetoothPanTest(blueberry_base_test.BlueberryBaseTest):
"""Test class for Bluetooth PAN(Personal Area Networking) profile.
Test internet connection sharing via Bluetooth between two Android devices.
One device which is referred to as NAP(Network Access Point) uses Bluetooth
tethering to share internet connection with another device which is referred
to as PANU(Personal Area Networking User).
"""
def setup_class(self):
"""Standard Mobly setup class."""
super(BluetoothPanTest, self).setup_class()
# Number of attempts to initiate connection. 5 attempts as default.
self.pan_connect_attempts = self.user_params.get('pan_connect_attempts', 5)
for device in self.android_devices:
device.init_setup()
device.sl4a_setup()
device.mac_address = device.get_bluetooth_mac_address()
# Check if the device has inserted a SIM card.
if device.sl4a.telephonyGetSimState() != SIM_STATE_READY:
raise signals.TestError('SIM card is not ready on Device "%s".' %
device.serial)
self.primary_device = self.android_devices[0]
self.secondary_device = self.android_devices[1]
def teardown_test(self):
"""Standard Mobly teardown test.
Reset every devices when a test finished.
"""
super(BluetoothPanTest, self).teardown_test()
# Revert debug tags.
for device in self.android_devices:
device.debug_tag = device.serial
device.factory_reset_bluetooth()
def wait_for_nap_service_connection(
self,
device,
connected_mac_addr,
state_connected=True):
"""Waits for NAP service connection to be expected state.
Args:
device: AndroidDevice, A device is used to check this connection.
connected_mac_addr: String, Bluetooth Mac address is needed to be checked.
state_connected: Bool, NAP service connection is established as expected
if True, else terminated as expected.
Raises:
TestFailure: Raised if NAP service connection is not expected state.
"""
def is_device_connected():
"""Returns True if connected else False."""
connected_devices = (device.sl4a.
bluetoothPanGetConnectedDevices())
# Check if the Bluetooth mac address is in the connected device list.
return connected_mac_addr in [d['address'] for d in connected_devices]
bt_test_utils.wait_until(
timeout_sec=CONNECTION_TIMEOUT_SECS,
condition_func=is_device_connected,
func_args=[],
expected_value=state_connected,
exception=signals.TestFailure(
'NAP service connection failed to be %s in %ds.' %
('established' if state_connected else 'terminated',
CONNECTION_TIMEOUT_SECS)))
def initiate_nap_service_connection(
self,
initiator_device,
connected_mac_addr):
"""Initiates NAP service connection.
Args:
initiator_device: AndroidDevice, A device intiating connection.
connected_mac_addr: String, Bluetooth Mac address of connected device.
Raises:
TestFailure: Raised if NAP service connection fails to be established.
"""
count = 0
for _ in range(self.pan_connect_attempts):
count += 1
try:
initiator_device.sl4a.bluetoothConnectBonded(connected_mac_addr)
self.wait_for_nap_service_connection(
device=initiator_device,
connected_mac_addr=connected_mac_addr,
state_connected=True)
return
except signals.TestFailure:
if count == self.pan_connect_attempts:
raise signals.TestFailure(
'NAP service connection still failed to be established '
'after retried %d times.' %
self.pan_connect_attempts)
def terminate_nap_service_connection(
self,
initiator_device,
connected_mac_addr):
"""Terminates NAP service connection.
Args:
initiator_device: AndroidDevice, A device intiating disconnection.
connected_mac_addr: String, Bluetooth Mac address of connected device.
"""
initiator_device.log.info('Terminate NAP service connection.')
initiator_device.sl4a.bluetoothDisconnectConnected(connected_mac_addr)
self.wait_for_nap_service_connection(
device=initiator_device,
connected_mac_addr=connected_mac_addr,
state_connected=False)
@contextlib.contextmanager
def establish_nap_service_connection(self, nap_device, panu_device):
"""Establishes NAP service connection between both Android devices.
The context is used to form a basic network connection between devices
before executing a test.
Steps:
1. Disable Mobile data to avoid internet access on PANU device.
2. Make sure Mobile data available on NAP device.
3. Enable Bluetooth from PANU device.
4. Enable Bluetooth tethering on NAP device.
5. Initiate a connection from PANU device.
6. Check if PANU device has internet access via the connection.
Args:
nap_device: AndroidDevice, A device sharing internet connection via
Bluetooth tethering.
panu_device: AndroidDevice, A device gaining internet access via
Bluetooth tethering.
Yields:
None, the context just execute a pre procedure for PAN testing.
Raises:
signals.TestError: raised if a step fails.
signals.TestFailure: raised if PANU device fails to access internet.
"""
nap_device.debug_tag = 'NAP'
panu_device.debug_tag = 'PANU'
try:
# Disable Mobile data to avoid internet access on PANU device.
panu_device.log.info('Disabling Mobile data...')
panu_device.sl4a.setMobileDataEnabled(False)
self.verify_internet(
allow_access=False,
device=panu_device,
exception=signals.TestError(
'PANU device "%s" still connected to internet when Mobile data '
'had been disabled.' % panu_device.serial))
# Make sure NAP device has Mobile data for internet sharing.
nap_device.log.info('Enabling Mobile data...')
nap_device.sl4a.setMobileDataEnabled(True)
self.verify_internet(
allow_access=True,
device=nap_device,
exception=signals.TestError(
'NAP device "%s" did not have internet access when Mobile data '
'had been enabled.' % nap_device.serial))
# Enable Bluetooth tethering from NAP device.
nap_device.set_bluetooth_tethering(status_enabled=True)
# Wait until Bluetooth tethering stabilizes. This waiting time avoids PANU
# device initiates a connection to NAP device immediately when NAP device
# enables Bluetooth tethering.
time.sleep(5)
nap_device.activate_pairing_mode()
panu_device.log.info('Pair to NAP device "%s".' % nap_device.serial)
panu_device.pair_and_connect_bluetooth(nap_device.mac_address)
# Initiate a connection to NAP device.
panu_device.log.info('Initiate a connection to NAP device "%s".' %
nap_device.serial)
self.initiate_nap_service_connection(
initiator_device=panu_device,
connected_mac_addr=nap_device.mac_address)
# Check if PANU device can access internet via NAP service connection.
self.verify_internet(
allow_access=True,
device=panu_device,
exception=signals.TestFailure(
'PANU device "%s" failed to access internet via NAP service '
'connection.' % panu_device.serial))
yield
finally:
# Disable Bluetooth tethering from NAP device.
nap_device.set_bluetooth_tethering(status_enabled=False)
panu_device.sl4a.setMobileDataEnabled(True)
def verify_internet(self, allow_access, device, exception):
"""Verifies that internet is in expected state.
Continuously make ping request to a URL for internet verification.
Args:
allow_access: Bool, Device can have internet access as expected if True,
else no internet access as expected.
device: AndroidDevice, Device to be check internet state.
exception: Exception, Raised if internet is not in expected state.
"""
device.log.info('Verify that internet %s be used.' %
('can' if allow_access else 'can not'))
def http_ping():
"""Returns True if http ping success else False."""
try:
return bool(device.sl4a.httpPing(TEST_URL))
except jsonrpc_client_base.ApiError as e:
# ApiError is raised by httpPing() when no internet.
device.log.debug(str(e))
return False
bt_test_utils.wait_until(
timeout_sec=PING_TIMEOUT_SEC,
condition_func=http_ping,
func_args=[],
expected_value=allow_access,
exception=exception,
interval_sec=PING_INTERVAL_TIME_SEC)
def test_gain_internet_and_terminate_nap_connection(self):
"""Test that DUT can access internet and terminate NAP service connection.
In this test case, primary device is PANU and secondary device is NAP. While
a connection has established between both devices, PANU should be able to
use internet and terminate the connection to disable internet access.
Steps:
1. Establish NAP service connection between both devices.
2. Terminal the connection from PANU device.
3. Verify that PANU device cannot access internet.
"""
with self.establish_nap_service_connection(
nap_device=self.secondary_device,
panu_device=self.primary_device):
# Terminate the connection from DUT.
self.terminate_nap_service_connection(
initiator_device=self.primary_device,
connected_mac_addr=self.secondary_device.mac_address)
# Verify that PANU device cannot access internet.
self.verify_internet(
allow_access=False,
device=self.primary_device,
exception=signals.TestFailure(
'PANU device "%s" can still access internet when it had '
'terminated NAP service connection.' %
self.primary_device.serial))
def test_share_internet_and_disable_bluetooth_tethering(self):
"""Test that DUT can share internet and stop internet sharing.
In this test case, primary device is NAP and secondary device is PANU. While
a connection has established between both devices, NAP should be able to
share internet and disable Bluetooth thethering to stop internet sharing.
Steps:
1. Establish NAP service connection between both devices.
3. Disable Bluetooth tethering from NAP device.
4. Verify that PANU device cannot access internet.
"""
with self.establish_nap_service_connection(
nap_device=self.primary_device,
panu_device=self.secondary_device):
# Disable Bluetooth tethering from DUT and check if the nap connection is
# terminated.
self.primary_device.set_bluetooth_tethering(status_enabled=False)
self.wait_for_nap_service_connection(
device=self.primary_device,
connected_mac_addr=self.secondary_device.mac_address,
state_connected=False)
# Verify that PANU device cannot access internet.
self.verify_internet(
allow_access=False,
device=self.secondary_device,
exception=signals.TestFailure(
'PANU device "%s" can still access internet when it had '
'terminated NAP service connection.' %
self.secondary_device.serial))
if __name__ == '__main__':
test_runner.main()