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