Home | History | Annotate | Download | only in beacon_tests
      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 This test script exercises different testcases with a lot of ble beacon traffic.
     18 
     19 This test script was designed with this setup in mind:
     20 Shield box one: Android Device as DUT. 7x Sprout devices acting as 192 beacons
     21 """
     22 
     23 import threading
     24 
     25 from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
     26 from acts.test_utils.bt.BleEnum import AdvertiseSettingsAdvertiseMode
     27 from acts.test_utils.bt.BleEnum import ScanSettingsScanMode
     28 from acts.test_utils.bt.bt_test_utils import adv_succ
     29 from acts.test_utils.bt.bt_test_utils import batch_scan_result
     30 from acts.test_utils.bt.bt_test_utils import scan_result
     31 from acts.test_utils.bt.bt_test_utils import generate_ble_advertise_objects
     32 from acts.test_utils.bt.bt_test_utils import generate_ble_scan_objects
     33 from acts.test_utils.bt.bt_test_utils import reset_bluetooth
     34 from acts.test_utils.bt.bt_test_utils import setup_multiple_devices_for_bt_test
     35 from acts.test_utils.bt.bt_test_utils import take_btsnoop_logs
     36 
     37 
     38 class BeaconSwarmTest(BluetoothBaseTest):
     39     default_timeout = 10
     40     beacon_swarm_count = 0
     41     advertising_device_name_list = []
     42     discovered_mac_address_list = []
     43 
     44     def __init__(self, controllers):
     45         BluetoothBaseTest.__init__(self, controllers)
     46         self.scn_ad = self.android_devices[0]
     47 
     48     def setup_test(self):
     49         self.discovered_mac_address_list = []
     50         for a in self.android_devices:
     51             a.ed.clear_all_events()
     52         return True
     53 
     54     def teardown_test(self):
     55         reset_bluetooth([self.android_devices[0]])
     56         return True
     57 
     58     def setup_class(self):
     59         if not setup_multiple_devices_for_bt_test(self.android_devices):
     60             return False
     61         return self._start_special_advertisements()
     62 
     63     def cleanup_class(self):
     64         return reset_bluetooth(self.android_devices)
     65 
     66     def on_fail(self, test_name, begin_time):
     67         take_btsnoop_logs(self.android_devices, self, test_name)
     68         reset_bluetooth([self.scn_ad])
     69 
     70     def _start_advertisements_thread(self, ad, beacon_count, restart=False):
     71         d, e = ad.droid, ad.ed
     72         if restart:
     73             try:
     74                 reset_bluetooth([ad])
     75             except Exception:
     76                 self.log.debug("Failed resetting Bluetooth, continuing...")
     77                 return
     78         try:
     79             for _ in range(beacon_count):
     80                 d.bleSetAdvertiseDataIncludeDeviceName(True)
     81                 d.bleSetAdvertiseSettingsAdvertiseMode(
     82                     AdvertiseSettingsAdvertiseMode.ADVERTISE_MODE_LOW_LATENCY.
     83                     value)
     84                 advertise_callback, advertise_data, advertise_settings = (
     85                     generate_ble_advertise_objects(d))
     86                 d.bleStartBleAdvertising(advertise_callback, advertise_data,
     87                                          advertise_settings)
     88                 try:
     89                     e.pop_event(
     90                         adv_succ.format(advertise_callback),
     91                         self.default_timeout)
     92                     self.beacon_swarm_count += 1
     93                     local_bt_name = d.bluetoothGetLocalName()
     94                     if local_bt_name not in self.advertising_device_name_list:
     95                         self.advertising_device_name_list.append(
     96                             d.bluetoothGetLocalName())
     97                 except Exception as e:
     98                     self.log.info("Advertising failed due to " + str(e))
     99                 self.log.info("Beacons active: {}".format(
    100                     self.beacon_swarm_count))
    101         except Exception:
    102             self.log.debug(
    103                 "Something went wrong in starting advertisements, continuing.")
    104         return
    105 
    106     def _start_special_advertisements(self):
    107         self.log.info("Setting up advertisements.")
    108         beacon_serials = []
    109         beacon_count = 0
    110         try:
    111             beacon_serials = self.user_params['beacon_devices']
    112             beacon_count = self.user_params['beacon_count']
    113         except AttributeError:
    114             self.log.info(
    115                 "No controllable devices connected to create beacons with."
    116                 " Continuing...")
    117         threads = []
    118         for a in self.android_devices:
    119             d, e = a.droid, a.ed
    120             serial_no = a.serial
    121             if serial_no not in beacon_serials:
    122                 continue
    123             thread = threading.Thread(target=self._start_advertisements_thread,
    124                                       args=(d, e, beacon_count))
    125             threads.append(thread)
    126             thread.start()
    127         for t in threads:
    128             t.join()
    129         if self.beacon_swarm_count < (beacon_count * len(beacon_serials)):
    130             self.log.error("Not enough beacons advertising: {}".format(
    131                 self.beacon_swarm_count))
    132             return False
    133         return True
    134 
    135     def _restart_special_advertisements_thread(self):
    136         beacon_serials = []
    137         beacon_count = 0
    138         try:
    139             beacon_serials = self.user_params['beacon_devices']
    140             beacon_count = self.user_params['beacon_count']
    141         except AttributeError:
    142             self.log.info("No controllable devices connected to create beacons"
    143                           " with. Continuing...")
    144         threads = []
    145         while True:
    146             self.log.info("Restarting advertisements.")
    147             for a in self.android_devices:
    148                 d, e = a.droid, a.ed
    149                 serial_no = a.serial
    150                 if serial_no not in beacon_serials:
    151                     continue
    152                 thread = threading.Thread(
    153                     target=self._start_advertisements_thread,
    154                     args=(d, e, beacon_count, True))
    155                 threads.append(thread)
    156                 thread.start()
    157             for t in threads:
    158                 t.join()
    159         return True
    160 
    161     def test_swarm_1000_on_scan_result(self):
    162         """Test LE scanning in a mass beacon deployment.
    163 
    164         Test finding 1000 LE scan results in a mass beacon deployment.
    165 
    166         Steps:
    167         1. Assume that mass beacon deployment is setup.
    168         2. Set LE scanning mode to low latency.
    169         3. Start LE scan.
    170         4. Pop scan results off the event dispatcher 1000 times.
    171         5. Stop LE scanning.
    172 
    173         Expected Result:
    174         1000 scan results should be found without any exceptions.
    175 
    176         Returns:
    177           Pass if True
    178           Fail if False
    179 
    180         TAGS: LE, Scanning, Beacon
    181         Priority: 1
    182         """
    183         self.scn_ad.droid.bleSetScanSettingsScanMode(
    184             ScanSettingsScanMode.SCAN_MODE_LOW_LATENCY.value)
    185         filter_list, scan_settings, scan_callback = generate_ble_scan_objects(
    186             self.scn_ad.droid)
    187         self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings,
    188                                           scan_callback)
    189         for _ in range(1000000):
    190             event_info = self.scn_ad.ed.pop_event(
    191                 scan_result.format(scan_callback), self.default_timeout)
    192             mac_address = event_info['data']['Result']['deviceInfo']['address']
    193             if mac_address not in self.discovered_mac_address_list:
    194                 self.discovered_mac_address_list.append(mac_address)
    195                 self.log.info("Discovered {} different devices.".format(len(
    196                     self.discovered_mac_address_list)))
    197         self.log.debug("Discovered {} different devices.".format(len(
    198             self.discovered_mac_address_list)))
    199         self.scn_ad.droid.bleStopBleScan(scan_callback)
    200         return True
    201 
    202     def test_swarm_10000_on_batch_scan_result(self):
    203         """Test LE batch scanning in a mass beacon deployment.
    204 
    205         Test finding 10000 LE batch scan results in a mass beacon deployment.
    206 
    207         Steps:
    208         1. Assume that mass beacon deployment is setup.
    209         2. Set LE scanning mode to low latency and report delay millis to 1
    210         second.
    211         3. Start LE scan.
    212         4. Pop batch scan results off the event dispatcher 10000 times.
    213         5. Stop LE scanning.
    214 
    215         Expected Result:
    216         1000 scan results should be found without any exceptions.
    217 
    218         Returns:
    219           Pass if True
    220           Fail if False
    221 
    222         TAGS: LE, Scanning, Beacon
    223         Priority: 1
    224         """
    225         self.scn_ad.droid.bleSetScanSettingsScanMode(
    226             ScanSettingsScanMode.SCAN_MODE_LOW_LATENCY.value)
    227         self.scn_ad.droid.bleSetScanSettingsReportDelayMillis(1000)
    228         filter_list, scan_settings, scan_callback = generate_ble_scan_objects(
    229             self.scn_ad.droid)
    230         self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings,
    231                                           scan_callback)
    232         for _ in range(10000):
    233             event_info = self.scn_ad.ed.pop_event(
    234                 batch_scan_result.format(scan_callback), self.default_timeout)
    235             for result in event_info['data']['Results']:
    236                 mac_address = result['deviceInfo']['address']
    237                 if mac_address not in self.discovered_mac_address_list:
    238                     self.discovered_mac_address_list.append(mac_address)
    239         self.log.info("Discovered {} different devices.".format(len(
    240             self.discovered_mac_address_list)))
    241         self.scn_ad.droid.bleStopBleScan(scan_callback)
    242         return True
    243 
    244     def test_swarm_scan_result_filter_each_device_name(self):
    245         """Test basic LE scan filtering in a mass beacon deployment.
    246 
    247         Test finding LE scan results in a mass beacon deployment. This
    248         test specifically tests scan filtering of different device names and
    249         that each device name is found.
    250 
    251         Steps:
    252         1. Assume that mass beacon deployment is setup with device names
    253         advertising.
    254         2. Set LE scanning mode to low latency.
    255         3. Filter device name from one of the known advertising device names
    256         4. Start LE scan.
    257         5. Pop scan results matching the scan filter.
    258         6. Stop LE scanning.
    259         7. Repeat steps 2-6 until all advertising device names are found.
    260 
    261         Expected Result:
    262         All advertising beacons are found by their device name.
    263 
    264         Returns:
    265           Pass if True
    266           Fail if False
    267 
    268         TAGS: LE, Scanning, Beacon, Filtering
    269         Priority: 1
    270         """
    271         for filter_name in self.advertising_device_name_list:
    272             self.scn_ad.droid.bleSetScanSettingsScanMode(
    273                 ScanSettingsScanMode.SCAN_MODE_LOW_LATENCY.value)
    274             filter_list, scan_settings, scan_callback = (
    275                 generate_ble_scan_objects(self.scn_ad.droid))
    276             try:
    277                 self.scn_ad.droid.bleSetScanFilterDeviceName(filter_name)
    278                 self.scn_ad.droid.bleBuildScanFilter(filter_list)
    279                 self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings,
    280                                                   scan_callback)
    281                 self.log.debug(self.scn_ad.ed.pop_event(
    282                     scan_result.format(scan_callback), self.default_timeout))
    283             except Exception:
    284                 self.log.info("Couldn't find advertiser name {}.".format(
    285                     filter_name))
    286                 return False
    287             self.scn_ad.droid.bleStopBleScan(scan_callback)
    288         return True
    289 
    290     def test_swarm_rotate_addresses(self):
    291         """Test basic LE scan filtering in a mass beacon deployment.
    292 
    293         Test finding LE scan results in a mass beacon deployment. This test
    294         rotates the mac address of the advertising devices at a consistent
    295         interval in order to make the scanning device think there are
    296         thousands of devices nearby.
    297 
    298         Steps:
    299         1. Assume that mass beacon deployment is setup with device names
    300         advertising.
    301         2. Set LE scanning mode to low latency on 28 scan instances.
    302         3. Start LE scan on each of the scan instances.
    303         5. Continuously Pop scan results matching the scan filter.
    304         6. Rotate mac address of each advertising device sequentially.
    305         7. 5-6 10,000 times.
    306         8. Stop LE scanning
    307 
    308         Expected Result:
    309         The Bluetooth stack doesn't crash.
    310 
    311         Returns:
    312           Pass if True
    313           Fail if False
    314 
    315         TAGS: LE, Scanning, Beacon
    316         Priority: 1
    317         """
    318         scan_callback_list = []
    319         for _ in range(28):
    320             self.scn_ad.droid.bleSetScanSettingsScanMode(
    321                 ScanSettingsScanMode.SCAN_MODE_LOW_LATENCY.value)
    322             filter_list, scan_settings, scan_callback = generate_ble_scan_objects(
    323                 self.scn_ad.droid)
    324             self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings,
    325                                               scan_callback)
    326             scan_callback_list.append(scan_callback)
    327         thread = threading.Thread(
    328             target=self._restart_special_advertisements_thread,
    329             args=())
    330         thread.start()
    331         n = 0
    332         while n < 10000:
    333             for cb in scan_callback_list:
    334                 event_info = self.scn_ad.ed.pop_event(
    335                     scan_result.format(cb), self.default_timeout)
    336                 mac_address = event_info['data']['Result']['deviceInfo'][
    337                     'address']
    338                 if mac_address not in self.discovered_mac_address_list:
    339                     self.discovered_mac_address_list.append(mac_address)
    340                 self.log.info("Discovered {} different devices.".format(len(
    341                     self.discovered_mac_address_list)))
    342                 n += 1
    343         self.scn_ad.droid.bleStopBleScan(scan_callback)
    344         return True
    345