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