#!/usr/bin/env python3 # # Copyright (C) 2016 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. """ Test script to exercises different ways Ble Advertisements can run in concurrency. This test was designed to be run in a shield box. """ import concurrent import os import time from queue import Empty from acts.test_decorators import test_tracker_info from acts_contrib.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest from acts_contrib.test_utils.bt.bt_test_utils import BtTestUtilsError from acts_contrib.test_utils.bt.bt_constants import ble_advertise_settings_modes from acts_contrib.test_utils.bt.bt_constants import ble_scan_settings_callback_types from acts_contrib.test_utils.bt.bt_constants import ble_scan_settings_modes from acts_contrib.test_utils.bt.bt_constants import adv_succ from acts_contrib.test_utils.bt.bt_test_utils import generate_ble_advertise_objects from acts_contrib.test_utils.bt.bt_test_utils import generate_ble_scan_objects from acts_contrib.test_utils.bt.bt_test_utils import get_advanced_droid_list from acts_contrib.test_utils.bt.bt_test_utils import reset_bluetooth from acts_contrib.test_utils.bt.bt_test_utils import scan_and_verify_n_advertisements from acts_contrib.test_utils.bt.bt_constants import scan_result from acts_contrib.test_utils.bt.bt_test_utils import setup_n_advertisements from acts_contrib.test_utils.bt.bt_test_utils import take_btsnoop_logs from acts_contrib.test_utils.bt.bt_test_utils import teardown_n_advertisements class ConcurrentBleAdvertisingTest(BluetoothBaseTest): default_timeout = 10 droid_list = [] max_advertisements = -1 def setup_class(self): super().setup_class() self.scn_ad = self.android_devices[0] self.adv_ad = self.android_devices[1] self.droid_list = get_advanced_droid_list(self.android_devices) self.max_advertisements = self.droid_list[1]['max_advertisements'] def setup_test(self): super().setup_test() return reset_bluetooth(self.android_devices) def _verify_n_advertisements(self, num_advertisements): try: advertise_callback_list = setup_n_advertisements( self.adv_ad, num_advertisements) except BtTestUtilsError: return False try: scan_and_verify_n_advertisements(self.scn_ad, num_advertisements) except BtTestUtilsError: return False teardown_n_advertisements(self.adv_ad, len(advertise_callback_list), advertise_callback_list) return True @BluetoothBaseTest.bt_test_wrap @test_tracker_info(uuid='abc03874-6d7a-4b5d-9f29-18731a102793') def test_max_advertisements_defaults(self): """Testing max advertisements. Test that a single device can have the max advertisements concurrently advertising. Steps: 1. Setup the scanning android device. 2. Setup the advertiser android device. 3. Start scanning on the max_advertisements as defined in the script. 4. Verify that all advertisements are found. Expected Result: All advertisements should start without errors. Returns: Pass if True Fail if False TAGS: LE, Advertising, Concurrency Priority: 0 """ return self._verify_n_advertisements(self.max_advertisements) @BluetoothBaseTest.bt_test_wrap @test_tracker_info(uuid='50ee137e-eb71-40ef-b72f-a5fd646190d2') def test_max_advertisements_include_device_name_and_filter_device_name( self): """Testing max advertisement variant. Test that a single device can have the max advertisements concurrently advertising. Include the device name as a part of the filter and advertisement data. Steps: 1. Setup the scanning android device. 2. Setup the advertiser android device. 3. Include device name in each advertisement. 4. Include device name filter in the scanner. 5. Start scanning on the max_advertisements as defined in the script. 6. Verify that all advertisements are found. Expected Result: All advertisements should start without errors. Returns: Pass if True Fail if False TAGS: LE, Advertising, Concurrency Priority: 2 """ self.adv_ad.droid.bleSetAdvertiseDataIncludeDeviceName(True) self.scn_ad.droid.bleSetScanFilterDeviceName( self.adv_ad.droid.bluetoothGetLocalName()) return self._verify_n_advertisements(self.max_advertisements) @BluetoothBaseTest.bt_test_wrap @test_tracker_info(uuid='f7e9ba2b-6286-4510-a8a0-f1df831056c0') def test_max_advertisements_exclude_device_name_and_filter_device_name( self): """Test max advertisement variant. Test that a single device can have the max advertisements concurrently advertising. Include the device name as a part of the filter but not the advertisement data. Steps: 1. Setup the scanning android device. 2. Setup the advertiser android device. 3. Include device name filter in the scanner. 4. Start scanning on the max_advertisements as defined in the script. 5. Verify that no advertisements are found. Expected Result: All advertisements should start without errors. Returns: Pass if True Fail if False TAGS: LE, Advertising, Concurrency Priority: 2 """ self.adv_ad.droid.bleSetAdvertiseDataIncludeDeviceName(False) self.scn_ad.droid.bleSetScanFilterDeviceName( self.adv_ad.droid.bluetoothGetLocalName()) return not self._verify_n_advertisements(self.max_advertisements) @BluetoothBaseTest.bt_test_wrap @test_tracker_info(uuid='6ce102d7-61e1-4ca0-bcfb-767437b86c2b') def test_max_advertisements_with_manufacturer_data(self): """Test max advertisement variant. Test that a single device can have the max advertisements concurrently advertising. Include the manufacturer data as a part of the filter and advertisement data. Steps: 1. Setup the scanning android device. 2. Setup the advertiser android device. 3. Include manufacturer data in each advertisement. 4. Include manufacturer data filter in the scanner. 5. Start scanning on the max_advertisements as defined in the script. 6. Verify that all advertisements are found. Expected Result: All advertisements should start without errors. Returns: Pass if True Fail if False TAGS: LE, Advertising, Concurrency Priority: 2 """ self.scn_ad.droid.bleSetScanFilterManufacturerData(1, [1]) self.adv_ad.droid.bleAddAdvertiseDataManufacturerId(1, [1]) return self._verify_n_advertisements(self.max_advertisements) @BluetoothBaseTest.bt_test_wrap @test_tracker_info(uuid='2fc7d5e8-1539-42a8-8681-ce0b8bfc0924') def test_max_advertisements_with_manufacturer_data_mask(self): """Test max advertisements variant. Test that a single device can have the max advertisements concurrently advertising. Include the manufacturer data mask as a part of the filter and advertisement data. Steps: 1. Setup the scanning android device. 2. Setup the advertiser android device. 3. Include manufacturer data in each advertisement. 4. Include manufacturer data mask filter in the scanner. 5. Start scanning on the max_advertisements as defined in the script. 6. Verify that all advertisements are found. Expected Result: All advertisements should start without errors. Returns: Pass if True Fail if False TAGS: LE, Advertising, Concurrency Priority: 2 """ self.scn_ad.droid.bleSetScanFilterManufacturerData(1, [1], [1]) self.adv_ad.droid.bleAddAdvertiseDataManufacturerId(1, [1]) return self._verify_n_advertisements(self.max_advertisements) @BluetoothBaseTest.bt_test_wrap @test_tracker_info(uuid='9ef615ed-1705-44ae-ab5b-f7e8fb4bb770') def test_max_advertisements_with_service_data(self): """Test max advertisement variant. Test that a single device can have the max advertisements concurrently advertising. Include the service data as a part of the filter and advertisement data. Steps: 1. Setup the scanning android device. 2. Setup the advertiser android device. 3. Include service data in each advertisement. 4. Include service data filter in the scanner. 5. Start scanning on the max_advertisements as defined in the script. 6. Verify that all advertisements are found. Expected Result: All advertisements should start without errors. Returns: Pass if True Fail if False TAGS: LE, Advertising, Concurrency Priority: 2 """ test_result = True filter_list = self.scn_ad.droid.bleGenFilterList() self.scn_ad.droid.bleSetScanFilterServiceData( "0000110A-0000-1000-8000-00805F9B34FB", [11, 17, 80]) self.adv_ad.droid.bleAddAdvertiseDataServiceData( "0000110A-0000-1000-8000-00805F9B34FB", [11, 17, 80]) return self._verify_n_advertisements(self.max_advertisements) @BluetoothBaseTest.bt_test_wrap @test_tracker_info(uuid='9ef615ed-1705-44ae-ab5b-f7e8fb4bb770') def test_max_advertisements_with_manufacturer_data_mask_and_include_device_name( self): """Test max advertisement variant. Test that a single device can have the max advertisements concurrently advertising. Include the device name and manufacturer data as a part of the filter and advertisement data. Steps: 1. Setup the scanning android device. 2. Setup the advertiser android device. 3. Include device name and manufacturer data in each advertisement. 4. Include device name and manufacturer data filter in the scanner. 5. Start scanning on the max_advertisements as defined in the script. 6. Verify that all advertisements are found. Expected Result: All advertisements should start without errors. Returns: Pass if True Fail if False TAGS: LE, Advertising, Concurrency Priority: 2 """ self.adv_ad.droid.bleSetAdvertiseDataIncludeDeviceName(True) self.scn_ad.droid.bleSetScanFilterDeviceName( self.adv_ad.droid.bluetoothGetLocalName()) self.scn_ad.droid.bleSetScanFilterManufacturerData(1, [1], [1]) self.adv_ad.droid.bleAddAdvertiseDataManufacturerId(1, [1]) return self._verify_n_advertisements(self.max_advertisements) @BluetoothBaseTest.bt_test_wrap @test_tracker_info(uuid='c2ca85fb-6663-431d-aa30-5286a85dbbe0') def test_max_advertisements_with_service_uuids(self): """Test max advertisement variant. Test that a single device can have the max advertisements concurrently advertising. Include the service uuid as a part of the filter and advertisement data. Steps: 1. Setup the scanning android device. 2. Setup the advertiser android device. 3. Include service uuid in each advertisement. 4. Include service uuid filter in the scanner. 5. Start scanning on the max_advertisements as defined in the script. 6. Verify that all advertisements are found. Expected Result: All advertisements should start without errors. Returns: Pass if True Fail if False TAGS: LE, Advertising, Concurrency Priority: 1 """ self.scn_ad.droid.bleSetScanFilterServiceUuid( "00000000-0000-1000-8000-00805f9b34fb") self.adv_ad.droid.bleSetAdvertiseDataSetServiceUuids( ["00000000-0000-1000-8000-00805f9b34fb"]) return self._verify_n_advertisements(self.max_advertisements) @BluetoothBaseTest.bt_test_wrap @test_tracker_info(uuid='756e026f-64d7-4a2f-935a-3790c0ac4503') def test_max_advertisements_with_service_uuid_and_service_mask(self): """Test max advertisements variant. Test that a single device can have the max advertisements concurrently advertising. Include the service mask as a part of the filter and advertisement data. Steps: 1. Setup the scanning android device. 2. Setup the advertiser android device. 3. Include service uuid in each advertisement. 4. Include service mask filter in the scanner. 5. Start scanning on the max_advertisements as defined in the script. 6. Verify that all advertisements are found. Expected Result: All advertisements should start without errors. Returns: Pass if True Fail if False TAGS: LE, Advertising, Concurrency Priority: 2 """ self.scn_ad.droid.bleSetScanFilterServiceUuid( "00000000-0000-1000-8000-00805f9b34fb", "00000000-0000-1000-8000-00805f9b34fb") self.adv_ad.droid.bleSetAdvertiseDataSetServiceUuids( ["00000000-0000-1000-8000-00805f9b34fb"]) return self._verify_n_advertisements(self.max_advertisements) @BluetoothBaseTest.bt_test_wrap @test_tracker_info(uuid='79c4b6cd-9f07-49a9-829f-69b29ea8d322') def test_max_advertisements_plus_one(self): """Test max advertisements plus one. Test that a single device can have the max advertisements concurrently advertising but fail on starting the max advertisements plus one. filter and advertisement data. Steps: 1. Setup the scanning android device. 2. Setup the advertiser android device. 3. Start max_advertisements + 1. Expected Result: The last advertisement should fail. Returns: Pass if True Fail if False TAGS: LE, Advertising, Concurrency Priority: 0 """ return not self._verify_n_advertisements(self.max_advertisements + 1) @BluetoothBaseTest.bt_test_wrap @test_tracker_info(uuid='0bd6e490-a501-4fe1-88e5-9b77970c0b95') def test_start_two_advertisements_on_same_callback(self): """Test invalid advertisement scenario. Test that a single device cannot have two advertisements start on the same callback. Steps: 1. Setup the scanning android device. 2. Setup the advertiser android device. 3. Call start ble advertising on the same callback. Expected Result: The second call of start advertising on the same callback should fail. Returns: Pass if True Fail if False TAGS: LE, Advertising, Concurrency Priority: 1 """ test_result = True advertise_callback, advertise_data, advertise_settings = ( generate_ble_advertise_objects(self.adv_ad.droid)) self.adv_ad.droid.bleStartBleAdvertising( advertise_callback, advertise_data, advertise_settings) try: self.adv_ad.ed.pop_event( adv_succ.format(advertise_callback), self.default_timeout) except Empty as error: self.log.error("Test failed with Empty error: {}".format(error)) return False except concurrent.futures._base.TimeoutError as error: self.log.debug( "Test failed, filtering callback onSuccess never occurred: {}" .format(error)) try: self.adv_ad.droid.bleStartBleAdvertising( advertise_callback, advertise_data, advertise_settings) self.adv_ad.ed.pop_event( adv_succ.format(advertise_callback), self.default_timeout) test_result = False except Empty as error: self.log.debug("Test passed with Empty error: {}".format(error)) except concurrent.futures._base.TimeoutError as error: self.log.debug( "Test passed, filtering callback onSuccess never occurred: {}" .format(error)) return test_result @BluetoothBaseTest.bt_test_wrap @test_tracker_info(uuid='12632b31-22b9-4121-80b6-1263b9d90909') def test_toggle_advertiser_bt_state(self): """Test forcing stopping advertisements. Test that a single device resets its callbacks when the bluetooth state is reset. There should be no advertisements. Steps: 1. Setup the scanning android device. 2. Setup the advertiser android device. 3. Call start ble advertising. 4. Toggle bluetooth on and off. 5. Scan for any advertisements. Expected Result: No advertisements should be found after toggling Bluetooth on the advertising device. Returns: Pass if True Fail if False TAGS: LE, Advertising, Concurrency Priority: 2 """ test_result = True self.adv_ad.droid.bleSetAdvertiseDataIncludeDeviceName(True) advertise_callback, advertise_data, advertise_settings = ( generate_ble_advertise_objects(self.adv_ad.droid)) self.adv_ad.droid.bleStartBleAdvertising( advertise_callback, advertise_data, advertise_settings) try: self.adv_ad.ed.pop_event( adv_succ.format(advertise_callback), self.default_timeout) except Empty as error: self.log.error("Test failed with Empty error: {}".format(error)) return False except concurrent.futures._base.TimeoutError as error: self.log.error( "Test failed, filtering callback onSuccess never occurred: {}". format(error)) self.scn_ad.droid.bleSetScanSettingsScanMode( ble_scan_settings_modes['low_latency']) self.scn_ad.droid.bleSetScanFilterDeviceName( self.adv_ad.droid.bluetoothGetLocalName()) filter_list, scan_settings, scan_callback = generate_ble_scan_objects( self.scn_ad.droid) self.scn_ad.droid.bleBuildScanFilter(filter_list) self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, scan_callback) try: self.scn_ad.ed.pop_event( scan_result.format(scan_callback), self.default_timeout) except Empty as error: self.log.error("Test failed with: {}".format(error)) return False self.scn_ad.droid.bleStopBleScan(scan_callback) test_result = reset_bluetooth([self.android_devices[1]]) self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, scan_callback) if not test_result: return False try: expected_event = scan_result.format(scan_callback) event = self.scn_ad.ed.pop_event(expected_event, self.default_timeout) self.log.error("Event {} not expected. Found: {}".format( expected_event, event)) return False except Empty as error: self.log.debug("Test passed with: {}".format(error)) self.scn_ad.droid.bleStopBleScan(scan_callback) self.adv_ad.droid.bleStopBleAdvertising(advertise_callback) return True @BluetoothBaseTest.bt_test_wrap @test_tracker_info(uuid='785c5c77-d5d4-4d0f-8b7b-3eb1f1646d2c') def test_restart_advertise_callback_after_bt_toggle(self): """Test starting an advertisement on a cleared out callback. Test that a single device resets its callbacks when the bluetooth state is reset. Steps: 1. Setup the scanning android device. 2. Setup the advertiser android device. 3. Call start ble advertising. 4. Toggle bluetooth on and off. 5. Call start ble advertising on the same callback. Expected Result: Starting an advertisement on a callback id after toggling bluetooth should fail. Returns: Pass if True Fail if False TAGS: LE, Advertising, Concurrency Priority: 1 """ test_result = True advertise_callback, advertise_data, advertise_settings = ( generate_ble_advertise_objects(self.adv_ad.droid)) self.adv_ad.droid.bleStartBleAdvertising( advertise_callback, advertise_data, advertise_settings) try: self.adv_ad.ed.pop_event( adv_succ.format(advertise_callback), self.default_timeout) except Empty as error: self.log.error("Test failed with Empty error: {}".format(error)) test_result = False except concurrent.futures._base.TimeoutError as error: self.log.debug( "Test failed, filtering callback onSuccess never occurred: {}". format(error)) test_result = reset_bluetooth([self.android_devices[1]]) if not test_result: return test_result self.adv_ad.droid.bleStartBleAdvertising( advertise_callback, advertise_data, advertise_settings) try: self.adv_ad.ed.pop_event( adv_succ.format(advertise_callback), self.default_timeout) except Empty as error: self.log.error("Test failed with Empty error: {}".format(error)) test_result = False except concurrent.futures._base.TimeoutError as error: self.log.debug( "Test failed, filtering callback onSuccess never occurred: {}". format(error)) return test_result @BluetoothBaseTest.bt_test_wrap @test_tracker_info(uuid='dd5529b7-6774-4580-8b29-d84568c15442') def test_timeout(self): """Test starting advertiser with timeout. Test that when a timeout is used, the advertiser is cleaned properly, and next one can be started. Steps: 1. Setup the advertiser android device with 4 second timeout. 2. Call start ble advertising. 3. Wait 5 seconds, to make sure advertiser times out. 4. Repeat steps 1-4 four times. Expected Result: Starting the advertising should succeed each time. Returns: Pass if True Fail if False TAGS: LE, Advertising, Concurrency Priority: 1 """ advertise_timeout_s = 4 num_iterations = 4 test_result = True for i in range(0, num_iterations): advertise_callback, advertise_data, advertise_settings = ( generate_ble_advertise_objects(self.adv_ad.droid)) self.adv_ad.droid.bleSetAdvertiseSettingsTimeout( advertise_timeout_s * 1000) self.adv_ad.droid.bleStartBleAdvertising( advertise_callback, advertise_data, advertise_settings) try: self.adv_ad.ed.pop_event( adv_succ.format(advertise_callback), self.default_timeout) except Empty as error: self.log.error("Test failed with Empty error: {}".format( error)) test_result = False except concurrent.futures._base.TimeoutError as error: self.log.debug( "Test failed, filtering callback onSuccess never occurred: {}". format(error)) if not test_result: return test_result time.sleep(advertise_timeout_s + 1) return test_result