1#!/usr/bin/env python3 2# 3# Copyright (C) 2016 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); you may not 6# use this file except in compliance with the License. You may obtain a copy of 7# 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, WITHOUT 13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14# License for the specific language governing permissions and limitations under 15# the License. 16""" 17Basic LE Stress tests. 18""" 19 20import concurrent 21import pprint 22import time 23 24from queue import Empty 25from acts.test_decorators import test_tracker_info 26from acts_contrib.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest 27from acts_contrib.test_utils.bt.bt_test_utils import BtTestUtilsError 28from acts_contrib.test_utils.bt.bt_test_utils import clear_bonded_devices 29from acts_contrib.test_utils.bt.bt_test_utils import generate_ble_advertise_objects 30from acts_contrib.test_utils.bt.bt_test_utils import generate_ble_scan_objects 31from acts_contrib.test_utils.bt.bt_test_utils import get_advanced_droid_list 32from acts_contrib.test_utils.bt.bt_test_utils import get_mac_address_of_generic_advertisement 33from acts_contrib.test_utils.bt.bt_test_utils import reset_bluetooth 34from acts_contrib.test_utils.bt.bt_constants import scan_result 35 36 37class BleStressTest(BluetoothBaseTest): 38 default_timeout = 10 39 PAIRING_TIMEOUT = 20 40 droid_list = [] 41 42 def setup_class(self): 43 super().setup_class() 44 self.droid_list = get_advanced_droid_list(self.android_devices) 45 self.scn_ad = self.android_devices[0] 46 self.adv_ad = self.android_devices[1] 47 48 def teardown_test(self): 49 super().teardown_test() 50 self.log_stats() 51 52 def bleadvertise_verify_onsuccess_handler(self, event): 53 test_result = True 54 self.log.debug("Verifying onSuccess event") 55 self.log.debug(pprint.pformat(event)) 56 return test_result 57 58 def _verify_successful_bond(self, target_address): 59 end_time = time.time() + self.PAIRING_TIMEOUT 60 self.log.info("Verifying devices are bonded") 61 while time.time() < end_time: 62 bonded_devices = self.scn_ad.droid.bluetoothGetBondedDevices() 63 if target_address in {d['address'] for d in bonded_devices}: 64 self.log.info("Successfully bonded to device") 65 return True 66 return False 67 68 @BluetoothBaseTest.bt_test_wrap 69 @test_tracker_info(uuid='22f98085-6ed8-4ad8-b62d-b8d1eae20b89') 70 def test_loop_scanning_1000(self): 71 """Stress start/stop scan instances. 72 73 This test will start and stop scan instances as fast as possible. This 74 will guarantee that the scan instances are properly being cleaned up 75 when the scan is stopped. 76 77 Steps: 78 1. Start a scan instance. 79 2. Stop the scan instance. 80 3. Repeat steps 1-2 1000 times. 81 82 Expected Result: 83 Neither starting or stopping scan instances causes any failures. 84 85 Returns: 86 Pass if True 87 Fail if False 88 89 TAGS: LE, Scanning, Stress 90 Priority: 1 91 """ 92 test_result = True 93 for _ in range(1000): 94 filter_list, scan_settings, scan_callback = generate_ble_scan_objects( 95 self.scn_ad.droid) 96 self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, 97 scan_callback) 98 self.scn_ad.droid.bleStopBleScan(scan_callback) 99 return test_result 100 101 @BluetoothBaseTest.bt_test_wrap 102 @test_tracker_info(uuid='6caa84c2-50ac-46f2-a5e5-f942fd2cd6f6') 103 def test_loop_scanning_100_verify_no_hci_timeout(self): 104 """Stress start/stop scan instances variant. 105 106 This test will start and stop scan instances with a one second timeout 107 in between each iteration. This testcase was added because the specific 108 timing combination caused hci timeouts. 109 110 Steps: 111 1. Start a scan instance. 112 2. Stop the scan instance. 113 3. Sleep for 1 second. 114 4. Repeat steps 1-3 100 times. 115 116 Expected Result: 117 Neither starting or stopping scan instances causes any failures. 118 119 Returns: 120 Pass if True 121 Fail if False 122 123 TAGS: LE, Scanning, Stress 124 Priority: 1 125 """ 126 for _ in range(self.droid_list[1]['max_advertisements']): 127 adv_callback, adv_data, adv_settings = generate_ble_advertise_objects( 128 self.adv_ad.droid) 129 self.adv_ad.droid.bleStartBleAdvertising(adv_callback, adv_data, 130 adv_settings) 131 for _ in range(100): 132 filter_list, scan_settings, scan_callback = generate_ble_scan_objects( 133 self.scn_ad.droid) 134 self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, 135 scan_callback) 136 self.log.info( 137 self.scn_ad.ed.pop_event(scan_result.format(scan_callback))) 138 self.scn_ad.droid.bleStopBleScan(scan_callback) 139 time.sleep(1) 140 return True 141 142 @BluetoothBaseTest.bt_test_wrap 143 @test_tracker_info(uuid='5e9e4c8d-b72e-4767-81e5-f907c1834430') 144 def test_loop_advertising_100(self): 145 """Stress start/stop advertising instances. 146 147 This test will start and stop advertising instances as fast as possible. 148 149 Steps: 150 1. Start a advertising instance. 151 2. Find that an onSuccess callback is triggered. 152 3. Stop the advertising instance. 153 4. Repeat steps 1-3 100 times. 154 155 Expected Result: 156 Neither starting or stopping advertising instances causes any failures. 157 158 Returns: 159 Pass if True 160 Fail if False 161 162 TAGS: LE, Advertising, Stress 163 Priority: 1 164 """ 165 test_result = True 166 for _ in range(100): 167 advertise_callback, advertise_data, advertise_settings = generate_ble_advertise_objects( 168 self.adv_ad.droid) 169 self.adv_ad.droid.bleStartBleAdvertising( 170 advertise_callback, advertise_data, advertise_settings) 171 expected_advertise_event_name = "".join( 172 ["BleAdvertise", 173 str(advertise_callback), "onSuccess"]) 174 worker = self.adv_ad.ed.handle_event( 175 self.bleadvertise_verify_onsuccess_handler, 176 expected_advertise_event_name, ([]), self.default_timeout) 177 try: 178 self.log.debug(worker.result(self.default_timeout)) 179 except Empty as error: 180 self.log.debug(" ".join( 181 ["Test failed with Empty error:", 182 str(error)])) 183 test_result = False 184 except concurrent.futures._base.TimeoutError as error: 185 self.log.debug(" ".join([ 186 "Test failed, filtering callback onSuccess never occurred:", 187 str(error) 188 ])) 189 test_result = False 190 self.adv_ad.droid.bleStopBleAdvertising(advertise_callback) 191 return test_result 192 193 @BluetoothBaseTest.bt_test_wrap 194 @test_tracker_info(uuid='11a2f51b-7178-4c32-bb5c-7eddd100a50f') 195 def test_restart_advertise_callback_after_bt_toggle(self): 196 """Test to reuse an advertise callback. 197 198 This will verify if advertising objects can be reused after a bluetooth 199 toggle. 200 201 Steps: 202 1. Start a advertising instance. 203 2. Find that an onSuccess callback is triggered. 204 3. Stop the advertising instance. 205 4. Toggle bluetooth off and on. 206 5. Start an advertising instance on the same objects used in step 1. 207 6. Find that an onSuccess callback is triggered. 208 209 Expected Result: 210 Advertisement should start successfully. 211 212 Returns: 213 Pass if True 214 Fail if False 215 216 TAGS: LE, Advertising, Stress 217 Priority: 1 218 """ 219 test_result = True 220 advertise_callback, advertise_data, advertise_settings = generate_ble_advertise_objects( 221 self.adv_ad.droid) 222 self.adv_ad.droid.bleStartBleAdvertising( 223 advertise_callback, advertise_data, advertise_settings) 224 expected_advertise_event_name = "".join( 225 ["BleAdvertise", 226 str(advertise_callback), "onSuccess"]) 227 worker = self.adv_ad.ed.handle_event( 228 self.bleadvertise_verify_onsuccess_handler, 229 expected_advertise_event_name, ([]), self.default_timeout) 230 try: 231 self.log.debug(worker.result(self.default_timeout)) 232 except Empty as error: 233 self.log.debug(" ".join( 234 ["Test failed with Empty error:", 235 str(error)])) 236 test_result = False 237 except concurrent.futures._base.TimeoutError as error: 238 self.log.debug(" ".join([ 239 "Test failed, filtering callback onSuccess never occurred:", 240 str(error) 241 ])) 242 test_result = reset_bluetooth([self.scn_ad]) 243 if not test_result: 244 return test_result 245 time.sleep(5) 246 self.adv_ad.droid.bleStartBleAdvertising( 247 advertise_callback, advertise_data, advertise_settings) 248 worker = self.adv_ad.ed.handle_event( 249 self.bleadvertise_verify_onsuccess_handler, 250 expected_advertise_event_name, ([]), self.default_timeout) 251 try: 252 self.log.debug(worker.result(self.default_timeout)) 253 except Empty as error: 254 self.log.debug(" ".join( 255 ["Test failed with Empty error:", 256 str(error)])) 257 test_result = False 258 except concurrent.futures._base.TimeoutError as error: 259 self.log.debug(" ".join([ 260 "Test failed, filtering callback onSuccess never occurred:", 261 str(error) 262 ])) 263 return test_result 264 265 @BluetoothBaseTest.bt_test_wrap 266 @test_tracker_info(uuid='88f3c068-41be-41df-920c-c0ecaae1a619') 267 def test_restart_scan_callback_after_bt_toggle(self): 268 """Test to reuse an scan callback. 269 270 This will verify if scan objects can be reused after a bluetooth 271 toggle. 272 273 Steps: 274 1. Start a scanning instance. 275 3. Stop the scanning instance. 276 4. Toggle bluetooth off and on. 277 5. Start an scanning instance on the same objects used in step 1. 278 279 Expected Result: 280 Scanner should start successfully. 281 282 Returns: 283 Pass if True 284 Fail if False 285 286 TAGS: LE, Scanning, Stress 287 Priority: 1 288 """ 289 test_result = True 290 filter_list, scan_settings, scan_callback = generate_ble_scan_objects( 291 self.scn_ad.droid) 292 self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, 293 scan_callback) 294 reset_bluetooth([self.scn_ad]) 295 self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, 296 scan_callback) 297 298 return test_result 299 300 @BluetoothBaseTest.bt_test_wrap 301 @test_tracker_info(uuid='ce8adfc0-384f-4751-9438-13a76cada8da') 302 def test_le_pairing(self): 303 """Test LE pairing transport stress 304 305 This will test LE pairing between two android devices. 306 307 Steps: 308 1. Start an LE advertisement on secondary device. 309 2. Find address from primary device. 310 3. Discover and bond to LE address. 311 4. Stop LE advertisement on secondary device. 312 5. Repeat steps 1-4 100 times 313 314 Expected Result: 315 LE pairing should pass 100 times. 316 317 Returns: 318 Pass if True 319 Fail if False 320 321 TAGS: LE, Scanning, Stress, Pairing 322 Priority: 1 323 """ 324 iterations = 100 325 for i in range(iterations): 326 try: 327 target_address, adv_callback, scan_callback = get_mac_address_of_generic_advertisement( 328 self.scn_ad, self.adv_ad) 329 except BtTestUtilsError as err: 330 self.log.error(err) 331 return False 332 self.log.info("Begin interation {}/{}".format(i + 1, iterations)) 333 self.scn_ad.droid.bluetoothStartPairingHelper() 334 self.adv_ad.droid.bluetoothStartPairingHelper() 335 start_time = self.start_timer() 336 self.scn_ad.droid.bluetoothDiscoverAndBond(target_address) 337 if not self._verify_successful_bond(target_address): 338 self.log.error("Failed to bond devices.") 339 return False 340 self.log.info("Total time (ms): {}".format(self.end_timer())) 341 if not self._verify_successful_bond(self.adv_ad.droid.bluetoothGetLocalAddress()): 342 self.log.error("Failed to bond BREDR devices.") 343 return False 344 if not self.scn_ad.droid.bluetoothUnbond(target_address): 345 self.log.error("Failed to unbond device from scanner.") 346 return False 347 time.sleep(2) 348 if not self.adv_ad.droid.bluetoothUnbond(self.scn_ad.droid.bluetoothGetLocalAddress()): 349 self.log.error("Failed to unbond device from advertiser.") 350 return False 351 self.adv_ad.droid.bleStopBleAdvertising(adv_callback) 352 self.scn_ad.droid.bleStopBleScan(scan_callback) 353 # Magic sleep to let unbonding finish 354 time.sleep(2) 355 return True 356