def test_discover_opportunistic_scan_result_off_secondary_scan_filter( self): """Test opportunistic scan result from secondary scan filter. Tests opportunistic scan where the secondary scan instance does not find an advertisement but the scan instance with scan mode set to opportunistic scan will find an advertisement. Steps: 1. Initialize advertiser and start advertisement on dut1 (make sure the advertisement is not advertising the device name) 2. Set scan settings to opportunistic scan on dut0 scan instance 3. Start scan scan from step 2 4. Try to find an event, expect none 5. Start a second scanner on dut0, with any other mode set and set the scan filter device name to "opp_test" 6. Pop onScanResults from the second scanner 7. Expect no events 8. Pop onScanResults from the first scanner Expected Result: Opportunistic scan instance finds an advertisement. Returns: Pass if True Fail if False TAGS: LE, Advertising, Scanning, Opportunistic Scan Priority: 1 """ self._setup_generic_advertisement() self.scn_ad.droid.bleSetScanSettingsScanMode( ScanSettingsScanMode.SCAN_MODE_OPPORTUNISTIC.value) filter_list, scan_settings, scan_callback = generate_ble_scan_objects( self.scn_ad.droid) self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, scan_callback) self.active_scan_callback_list.append(scan_callback) if not self._verify_no_events_found(scan_result.format(scan_callback)): return False self.scn_ad.droid.bleSetScanSettingsScanMode( ScanSettingsScanMode.SCAN_MODE_LOW_LATENCY.value) self.scn_ad.droid.bleSetScanFilterDeviceName("opp_test") filter_list2, scan_settings2, scan_callback2 = ( generate_ble_scan_objects(self.scn_ad.droid)) self.scn_ad.droid.bleBuildScanFilter(filter_list2) self.scn_ad.droid.bleStartBleScan(filter_list2, scan_settings2, scan_callback2) self.active_scan_callback_list.append(scan_callback2) if not self._verify_no_events_found(scan_result.format( scan_callback2)): return False try: self.scn_ad.ed.pop_event( scan_result.format(scan_callback), self.default_timeout) except Empty: self.log.error("Opportunistic scan found no scan results.") return False return True
def test_scan_result(self): """Test opportunistic scan with an advertisement. Tests opportunistic scan where it will only report scan results when other registered scanners find results. Steps: 1. Initialize advertiser and start advertisement on dut1 2. Initialize scanner with scan mode set to opportunistic mode on dut0 and start scanning 3. Try to find an event, expect none. 4. Start a second scanner on dut0, with any other mode set 5. Pop onScanResults event on the second scanner 6. Pop onScanResults event on the first scanner Expected Result: Scan result is found on the opportunistic scan instance. Returns: Pass if True Fail if False TAGS: LE, Advertising, Scanning, Opportunistic Scan Priority: 1 """ self._setup_generic_advertisement() self.scn_ad.droid.bleSetScanSettingsScanMode( ScanSettingsScanMode.SCAN_MODE_OPPORTUNISTIC.value) filter_list, scan_settings, scan_callback = generate_ble_scan_objects( self.scn_ad.droid) self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, scan_callback) self.active_scan_callback_list.append(scan_callback) if not self._verify_no_events_found(scan_result.format(scan_callback)): return False self.scn_ad.droid.bleSetScanSettingsScanMode( ScanSettingsScanMode.SCAN_MODE_LOW_LATENCY.value) filter_list2, scan_settings2, scan_callback2 = ( generate_ble_scan_objects(self.scn_ad.droid)) self.scn_ad.droid.bleStartBleScan(filter_list2, scan_settings2, scan_callback2) self.active_scan_callback_list.append(scan_callback2) try: self.scn_ad.ed.pop_event(scan_result.format(scan_callback2), self.default_timeout) except Empty: self.log.error("Non-Opportunistic scan found no scan results.") return False try: self.scn_ad.ed.pop_event(scan_result.format(scan_callback), self.default_timeout) except Empty: self.log.error("Opportunistic scan found no scan results.") return False return True
def test_scan_result_no_advertisement(self): """Test opportunistic scan with no advertisement. Tests opportunistic scan where there are no advertisements. This should not find any onScanResults. Steps: 1. Initialize scanner with scan mode set to opportunistic mode. 2. Start scanning on dut 0 3. Pop onScanResults event on the scanner Expected Result: Find no advertisements with the opportunistic scan instance. Returns: Pass if True Fail if False TAGS: LE, Advertising, Scanning, Opportunistic Scan Priority: 1 """ self.scn_ad.droid.bleSetScanSettingsScanMode( ScanSettingsScanMode.SCAN_MODE_OPPORTUNISTIC.value) filter_list, scan_settings, scan_callback = generate_ble_scan_objects( self.scn_ad.droid) self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, scan_callback) self.active_scan_callback_list.append(scan_callback) if not self._verify_no_events_found(scan_result.format(scan_callback)): return False self.scn_ad.droid.bleStopBleScan(scan_callback) return True
def test_scan_advertisement_with_device_service_uuid_filter_expect_no_events( self): """Test scan filtering against an advertisement with no data. Test that exercises a service uuid filter on the scanner but no server uuid added to the advertisement. Steps: 1. Setup the scanning android device with scan filter including a service uuid and mask. 2. Setup the advertiser android devices. 3. Verify that no onScanResults were triggered. Expected Result: Verify no advertisements found. Returns: Pass if True Fail if False TAGS: LE, Advertising, Filtering, Scanning Priority: 1 """ test_result = True service_uuid = "00000000-0000-1000-8000-00805F9B34FB" service_mask = "00000000-0000-1000-8000-00805F9B34FA" self.adv_ad.droid.bleSetAdvertiseDataIncludeDeviceName(True) self.scn_ad.droid.bleSetScanFilterServiceUuid(service_uuid, service_mask) self.adv_ad.droid.bleSetAdvertiseSettingsAdvertiseMode( AdvertiseSettingsAdvertiseMode.ADVERTISE_MODE_LOW_LATENCY.value) filter_list, scan_settings, scan_callback = generate_ble_scan_objects( self.scn_ad.droid) self.scn_ad.droid.bleBuildScanFilter(filter_list) expected_event_name = scan_result.format(scan_callback) self.adv_ad.droid.bleSetAdvertiseDataIncludeDeviceName(True) self.adv_ad.droid.bleSetAdvertiseDataIncludeTxPowerLevel(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) self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, scan_callback) worker = self.scn_ad.ed.handle_event( self.blescan_verify_onscanresult_event_handler, expected_event_name, ([1]), self.default_timeout) try: event_info = self.scn_ad.ed.pop_event(expected_event_name, self.default_timeout) self.log.error( "Unexpectedly found an advertiser:".format(event_info)) test_result = False except Empty as error: self.log.debug("No events were found as expected.") self.scn_ad.droid.bleStopBleScan(scan_callback) self.adv_ad.droid.bleStopBleAdvertising(advertise_callback) return test_result
def test_background_scan(self): """Test generic background scan. Tests LE background scan. The goal is to find scan results even though Bluetooth is turned off. Steps: 1. Setup an advertisement on dut1 2. Enable LE on the Bluetooth Adapter on dut0 3. Toggle BT off on dut1 4. Start a LE scan on dut0 5. Find the advertisement from dut1 Expected Result: Find a advertisement from the scan instance. Returns: Pass if True Fail if False TAGS: LE, Advertising, Scanning, Background Scanning Priority: 0 """ import time self._setup_generic_advertisement() self.scn_ad.droid.bluetoothToggleState(False) try: self.scn_ad.ed.pop_event(bluetooth_off, self.default_timeout) except Empty: self.log.error("Bluetooth Off event not found. Expected {}".format( bluetooth_off)) return False self.scn_ad.droid.bluetoothDisableBLE() try: self.scn_ad.ed.pop_event(bluetooth_off, self.default_timeout) except Empty: self.log.error("Bluetooth Off event not found. Expected {}".format( bluetooth_off)) return False self.scn_ad.droid.bluetoothEnableBLE() try: self.scn_ad.ed.pop_event(bluetooth_off, self.default_timeout * 2) except Empty: self.log.error("Bluetooth On event not found. Expected {}".format( bluetooth_on)) return False filter_list, scan_settings, scan_callback = generate_ble_scan_objects( self.scn_ad.droid) self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, scan_callback) expected_event = scan_result.format(scan_callback) try: self.scn_ad.ed.pop_event(expected_event, self.default_timeout) except Empty: self.log.error("Scan Result event not found. Expected {}".format( expected_event)) return False return True
def test_swarm_rotate_addresses(self): """Test basic LE scan filtering in a mass beacon deployment. Test finding LE scan results in a mass beacon deployment. This test rotates the mac address of the advertising devices at a consistent interval in order to make the scanning device think there are thousands of devices nearby. Steps: 1. Assume that mass beacon deployment is setup with device names advertising. 2. Set LE scanning mode to low latency on 28 scan instances. 3. Start LE scan on each of the scan instances. 5. Continuously Pop scan results matching the scan filter. 6. Rotate mac address of each advertising device sequentially. 7. 5-6 10,000 times. 8. Stop LE scanning Expected Result: The Bluetooth stack doesn't crash. Returns: Pass if True Fail if False TAGS: LE, Scanning, Beacon Priority: 1 """ scan_callback_list = [] for _ in range(28): self.scn_ad.droid.bleSetScanSettingsScanMode( ScanSettingsScanMode.SCAN_MODE_LOW_LATENCY.value) filter_list, scan_settings, scan_callback = generate_ble_scan_objects( self.scn_ad.droid) self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, scan_callback) scan_callback_list.append(scan_callback) thread = threading.Thread( target=self._restart_special_advertisements_thread, args=()) thread.start() n = 0 while n < 10000: for cb in scan_callback_list: event_info = self.scn_ad.ed.pop_event(scan_result.format(cb), self.default_timeout) mac_address = event_info['data']['Result']['deviceInfo'][ 'address'] if mac_address not in self.discovered_mac_address_list: self.discovered_mac_address_list.append(mac_address) self.log.info("Discovered {} different devices.".format( len(self.discovered_mac_address_list))) n += 1 self.scn_ad.droid.bleStopBleScan(scan_callback) return True
def test_max_opportunistic_scan_instances(self): """Test max number of opportunistic scan instances. Tests max instances of opportunistic scans. Each instances should find an onScanResults event. Steps: 1. Initialize advertiser and start advertisement on dut1 2. Set scan settings to opportunistic scan on dut0 scan instance 3. Start scan scan from step 2 4. Repeat step two and three until there are max_scan_instances-1 scan instances 5. Start a regular ble scan on dut0 with the last available scan instance 6. Pop onScanResults event on all scan instances Expected Result: Each opportunistic scan instance finds a advertisement. Returns: Pass if True Fail if False TAGS: LE, Advertising, Scanning, Opportunistic Scan Priority: 1 """ self._setup_generic_advertisement() for _ in range(self.max_scan_instances - 1): self.scn_ad.droid.bleSetScanSettingsScanMode( ScanSettingsScanMode.SCAN_MODE_OPPORTUNISTIC.value) filter_list, scan_settings, scan_callback = generate_ble_scan_objects( self.scn_ad.droid) self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, scan_callback) self.active_scan_callback_list.append(scan_callback) self.scn_ad.droid.bleSetScanSettingsScanMode( ScanSettingsScanMode.SCAN_MODE_LOW_LATENCY.value) filter_list2, scan_settings2, scan_callback2 = ( generate_ble_scan_objects(self.scn_ad.droid)) self.scn_ad.droid.bleStartBleScan(filter_list2, scan_settings2, scan_callback2) self.active_scan_callback_list.append(scan_callback2) for callback in self.active_scan_callback_list: try: self.scn_ad.ed.pop_event(scan_result.format(callback), self.default_timeout) except Empty: self.log.error( "No scan results found for callback {}".format(callback)) return False return True
def test_scan_flush_pending_scan_results(self): """Test LE scan api flush pending results. Test that flush pending scan results doesn't affect onScanResults from triggering. Steps: 1. Setup the scanning android device. 2. Setup the advertiser android devices. 3. Trigger bluetoothFlushPendingScanResults on the scanning droid. 4. Verify that only one onScanResults callback was triggered. Expected Result: After flushing pending scan results, make sure only one onScanResult callback was triggered. Returns: Pass if True Fail if False TAGS: LE, Advertising, Filtering, Scanning Priority: 1 """ test_result = True self.adv_ad.droid.bleSetAdvertiseSettingsAdvertiseMode( AdvertiseSettingsAdvertiseMode.ADVERTISE_MODE_LOW_LATENCY.value) filter_list, scan_settings, scan_callback = generate_ble_scan_objects( self.scn_ad.droid) expected_event_name = scan_result.format(scan_callback) 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) self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, scan_callback) self.scn_ad.droid.bleFlushPendingScanResults(scan_callback) worker = self.scn_ad.ed.handle_event( self.blescan_verify_onscanresult_event_handler, expected_event_name, ([1]), self.default_timeout) try: self.log.debug(worker.result(self.default_timeout)) except Empty as error: test_result = False self.log.debug("Test failed with Empty error: {}".format(error)) except concurrent.futures._base.TimeoutError as error: test_result = False self.log.debug("Test failed with TimeoutError: {}".format(error)) self.scn_ad.droid.bleStopBleScan(scan_callback) self.adv_ad.droid.bleStopBleAdvertising(advertise_callback) return test_result
def test_scan_non_existent_name_filter(self): """Test non-existent name filter. Test scan filter on non-existent device name. Steps: 1. Setup the scanning android device with scan filter for device name set to an unexpected value. 2. Setup the advertiser android devices. 3. Verify that no onScanResults were triggered. Expected Result: No advertisements were found. Returns: Pass if True Fail if False TAGS: LE, Advertising, Filtering, Scanning Priority: 2 """ test_result = True filter_name = "{}_probably_wont_find".format( self.adv_ad.droid.bluetoothGetLocalName()) self.adv_ad.droid.bleSetAdvertiseDataIncludeDeviceName(True) self.scn_ad.droid.bleSetScanFilterDeviceName(filter_name) filter_list, scan_settings, scan_callback = generate_ble_scan_objects( self.scn_ad.droid) self.scn_ad.droid.bleBuildScanFilter(filter_list) expected_event_name = scan_result.format(scan_callback) self.adv_ad.droid.bleSetAdvertiseDataIncludeDeviceName(True) self.adv_ad.droid.bleSetAdvertiseDataIncludeTxPowerLevel(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) self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, scan_callback) try: event_info = self.scn_ad.ed.pop_event(expected_event_name, self.default_timeout) self.log.error( "Unexpectedly found an advertiser: {}".format(event_info)) test_result = False except Empty: self.log.debug("No events were found as expected.") self.scn_ad.droid.bleStopBleScan(scan_callback) self.adv_ad.droid.bleStopBleAdvertising(advertise_callback) return test_result
def test_swarm_scan_result_filter_each_device_name(self): """Test basic LE scan filtering in a mass beacon deployment. Test finding LE scan results in a mass beacon deployment. This test specifically tests scan filtering of different device names and that each device name is found. Steps: 1. Assume that mass beacon deployment is setup with device names advertising. 2. Set LE scanning mode to low latency. 3. Filter device name from one of the known advertising device names 4. Start LE scan. 5. Pop scan results matching the scan filter. 6. Stop LE scanning. 7. Repeat steps 2-6 until all advertising device names are found. Expected Result: All advertising beacons are found by their device name. Returns: Pass if True Fail if False TAGS: LE, Scanning, Beacon, Filtering Priority: 1 """ for filter_name in self.advertising_device_name_list: self.scn_ad.droid.bleSetScanSettingsScanMode( ScanSettingsScanMode.SCAN_MODE_LOW_LATENCY.value) filter_list, scan_settings, scan_callback = ( generate_ble_scan_objects(self.scn_ad.droid)) try: self.scn_ad.droid.bleSetScanFilterDeviceName(filter_name) self.scn_ad.droid.bleBuildScanFilter(filter_list) self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, scan_callback) self.log.debug( self.scn_ad.ed.pop_event(scan_result.format(scan_callback), self.default_timeout)) except Exception: self.log.info( "Couldn't find advertiser name {}.".format(filter_name)) return False self.scn_ad.droid.bleStopBleScan(scan_callback) return True
def _is_peripheral_advertising(self): self.cen_ad.droid.bleSetScanFilterDeviceAddress(self.ble_mac_address) self.cen_ad.droid.bleSetScanSettingsScanMode( ScanSettingsScanMode.SCAN_MODE_LOW_LATENCY.value) filter_list, scan_settings, scan_callback = generate_ble_scan_objects( self.cen_ad.droid) self.cen_ad.droid.bleStartBleScan(filter_list, scan_settings, scan_callback) expected_event_name = scan_result.format(scan_callback) test_result = True try: self.cen_ad.ed.pop_event(expected_event_name, self.DEFAULT_TIMEOUT) self.log.info( "Peripheral found with event: {}".format(expected_event_name)) except Empty: self.log.info("Peripheral not advertising or not found: {}".format( self.ble_mac_address)) test_result = False self.cen_ad.droid.bleStopBleScan(scan_callback) return test_result
def test_swarm_1000_on_scan_result(self): """Test LE scanning in a mass beacon deployment. Test finding 1000 LE scan results in a mass beacon deployment. Steps: 1. Assume that mass beacon deployment is setup. 2. Set LE scanning mode to low latency. 3. Start LE scan. 4. Pop scan results off the event dispatcher 1000 times. 5. Stop LE scanning. Expected Result: 1000 scan results should be found without any exceptions. Returns: Pass if True Fail if False TAGS: LE, Scanning, Beacon Priority: 1 """ self.scn_ad.droid.bleSetScanSettingsScanMode( ScanSettingsScanMode.SCAN_MODE_LOW_LATENCY.value) filter_list, scan_settings, scan_callback = generate_ble_scan_objects( self.scn_ad.droid) self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, scan_callback) for _ in range(1000000): event_info = self.scn_ad.ed.pop_event( scan_result.format(scan_callback), self.default_timeout) mac_address = event_info['data']['Result']['deviceInfo']['address'] if mac_address not in self.discovered_mac_address_list: self.discovered_mac_address_list.append(mac_address) self.log.info("Discovered {} different devices.".format( len(self.discovered_mac_address_list))) self.log.debug("Discovered {} different devices.".format( len(self.discovered_mac_address_list))) self.scn_ad.droid.bleStopBleScan(scan_callback) return True
def test_loop_scanning_100_verify_no_hci_timeout(self): """Stress start/stop scan instances variant. This test will start and stop scan instances with a one second timeout in between each iteration. This testcase was added because the specific timing combination caused hci timeouts. Steps: 1. Start a scan instance. 2. Stop the scan instance. 3. Sleep for 1 second. 4. Repeat steps 1-3 100 times. Expected Result: Neither starting or stopping scan instances causes any failures. Returns: Pass if True Fail if False TAGS: LE, Scanning, Stress Priority: 1 """ for _ in range(self.droid_list[1]['max_advertisements']): adv_callback, adv_data, adv_settings = generate_ble_advertise_objects( self.adv_ad.droid) self.adv_ad.droid.bleStartBleAdvertising(adv_callback, adv_data, adv_settings) for _ in range(100): filter_list, scan_settings, scan_callback = generate_ble_scan_objects( self.scn_ad.droid) self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, scan_callback) self.log.info( self.scn_ad.ed.pop_event(scan_result.format(scan_callback))) self.scn_ad.droid.bleStopBleScan(scan_callback) time.sleep(1) return True
def test_start_ble_scan(self): """Test to demonstrate how to start an LE scan Test that shows the steps to start a new ble scan. Steps: 1. Create a scan filter object. 2. Create a scan setting object. 3. Create a scan callback object. 4. Start an LE scan using the objects created in steps 1-3. 5. Find an advertisement with the scanner's event dispatcher. Expected Result: A generic advertisement is found. Returns: Pass if True Fail if False TAGS: LE, Scanning Priority: 4 """ filter_list = self.scn_droid.bleGenFilterList() scan_settings = self.scn_droid.bleBuildScanSetting() scan_callback = self.scn_droid.bleGenScanCallback() self.scn_droid.bleStartBleScan(filter_list, scan_settings, scan_callback) self.active_scan_callback_list.append(scan_callback) event_name = scan_result.format(scan_callback) try: event = self.scn_ed.pop_event(event_name, self.default_timeout) self.log.info("Found scan result: {}".format( pprint.pformat(event))) except Exception: self.log.info("Didn't find any scan results.") return True
def test_max_concurrent_ble_scans(self): """Test max LE scans. Test that a single device can have max scans concurrently scanning. Steps: 1. Initialize scanner 2. Initialize advertiser 3. Start advertising on the device from step 2 4. Create max ble scan callbacks 5. Start ble scan on each callback 6. Verify that each callback triggers 7. Stop all scans and advertisements Expected Result: All scanning instances should start without errors and the advertisement should be found on each scan instance. Returns: Pass if True Fail if False TAGS: LE, Scanning, Concurrency Priority: 0 """ test_result = True self.adv_ad.droid.bleSetAdvertiseDataIncludeDeviceName(True) self.scn_ad.droid.bleSetScanSettingsCallbackType( ScanSettingsCallbackType.CALLBACK_TYPE_ALL_MATCHES.value) self.scn_ad.droid.bleSetScanSettingsScanMode( ScanSettingsScanMode.SCAN_MODE_LOW_LATENCY.value) self.adv_ad.droid.bleSetAdvertiseSettingsAdvertiseMode( AdvertiseSettingsAdvertiseMode.ADVERTISE_MODE_LOW_LATENCY.value) advertise_callback, advertise_data, advertise_settings = ( generate_ble_advertise_objects(self.adv_ad.droid)) self.adv_ad.droid.bleSetAdvertiseSettingsIsConnectable(False) 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.exception( "Test failed with Empty error: {}".format(error)) test_result = False except concurrent.futures._base.TimeoutError as error: self.log.exception( "Test failed callback onSuccess never occurred: " "{}".format(error)) test_result = False if not test_result: return test_result filter_list = self.scn_ad.droid.bleGenFilterList() self.scn_ad.droid.bleSetScanFilterDeviceName( self.adv_ad.droid.bluetoothGetLocalName()) self.scn_ad.droid.bleBuildScanFilter(filter_list) scan_settings = self.scn_ad.droid.bleBuildScanSetting() scan_callback_list = [] for i in range(self.max_concurrent_scans): self.log.debug("Concurrent Ble Scan iteration {}".format(i + 1)) scan_callback = self.scn_ad.droid.bleGenScanCallback() scan_callback_list.append(scan_callback) 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) self.log.info("Found scan event successfully. Iteration {} " "successful.".format(i)) except Exception: self.log.info( "Failed to find a scan result for callback {}".format( scan_callback)) test_result = False break for callback in scan_callback_list: self.scn_ad.droid.bleStopBleScan(callback) self.adv_ad.droid.bleStopBleAdvertising(advertise_callback) if not test_result: return test_result self.log.info("Waiting for scan callbacks to stop completely.") # Wait for all scan callbacks to stop. There is no confirmation # otherwise. time.sleep(10) return test_result
def test_max_concurrent_ble_scans_verify_scans_stop_independently(self): """Test max LE scans variant. Test that a single device can have max scans concurrently scanning. Steps: 1. Initialize scanner 2. Initialize advertiser 3. Create max ble scan callbacks 4. Start ble scan on each callback 5. Start advertising on the device from step 2 6. Verify that the first callback triggers 7. Stop the scan and repeat steps 6 and 7 until all scans stopped Expected Result: All scanning instances should start without errors and the advertisement should be found on each scan instance. All scanning instances should stop successfully. Returns: Pass if True Fail if False TAGS: LE, Scanning, Concurrency Priority: 1 """ self.adv_ad.droid.bleSetAdvertiseDataIncludeDeviceName(True) self.scn_ad.droid.bleSetScanSettingsCallbackType( ScanSettingsCallbackType.CALLBACK_TYPE_ALL_MATCHES.value) self.scn_ad.droid.bleSetScanSettingsScanMode( ScanSettingsScanMode.SCAN_MODE_LOW_LATENCY.value) self.adv_ad.droid.bleSetAdvertiseSettingsAdvertiseMode( AdvertiseSettingsAdvertiseMode.ADVERTISE_MODE_LOW_LATENCY.value) advertise_callback, advertise_data, advertise_settings = ( generate_ble_advertise_objects(self.adv_ad.droid)) filter_list = self.scn_ad.droid.bleGenFilterList() self.scn_ad.droid.bleSetScanFilterDeviceName( self.adv_ad.droid.bluetoothGetLocalName()) self.scn_ad.droid.bleBuildScanFilter(filter_list) scan_settings = self.scn_ad.droid.bleBuildScanSetting() scan_callback_list = [] for i in range(self.max_concurrent_scans): self.log.debug("Concurrent Ble Scan iteration {}".format(i + 1)) scan_callback = self.scn_ad.droid.bleGenScanCallback() scan_callback_list.append(scan_callback) self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, scan_callback) 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.exception( "Test failed with Empty error: {}".format(error)) return False except concurrent.futures._base.TimeoutError as error: self.log.exception( "Test failed, filtering callback onSuccess never" " occurred: {}".format(error)) return False i = 0 for callback in scan_callback_list: expected_scan_event_name = scan_result.format(scan_callback) try: self.scn_ad.ed.pop_event(expected_scan_event_name, self.default_timeout) self.log.info( "Found scan event successfully. Iteration {} successful.". format(i)) i += 1 except Exception: self.log.info( "Failed to find a scan result for callback {}".format( scan_callback)) return False self.scn_ad.droid.bleStopBleScan(callback) self.adv_ad.droid.bleStopBleAdvertising(advertise_callback) return True
def _magic(self, params): (filters, settings_in_effect) = params test_result = True self.log.debug("Settings in effect: {}".format(pprint.pformat( settings_in_effect))) self.log.debug("Filters:".format(pprint.pformat(filters))) if 'is_connectable' in settings_in_effect.keys(): self.log.debug("Setting advertisement is_connectable to {}".format( settings_in_effect['is_connectable'])) self.adv_ad.droid.bleSetAdvertiseSettingsIsConnectable( settings_in_effect['is_connectable']) if 'mode' in settings_in_effect.keys(): self.log.debug("Setting advertisement mode to {}" .format(settings_in_effect['mode'])) self.adv_ad.droid.bleSetAdvertiseSettingsAdvertiseMode( settings_in_effect['mode']) if 'tx_power_level' in settings_in_effect.keys(): self.log.debug("Setting advertisement tx_power_level to {}".format( settings_in_effect['tx_power_level'])) self.adv_ad.droid.bleSetAdvertiseSettingsTxPowerLevel( settings_in_effect['tx_power_level']) filter_list = self.scn_ad.droid.bleGenFilterList() if ('include_device_name' in filters.keys() and filters['include_device_name'] is not False): self.log.debug("Setting advertisement include_device_name to {}" .format(filters['include_device_name'])) self.adv_ad.droid.bleSetAdvertiseDataIncludeDeviceName(True) filters['include_device_name'] = ( self.adv_ad.droid.bluetoothGetLocalName()) self.log.debug("Setting scanner include_device_name to {}".format( filters['include_device_name'])) self.scn_ad.droid.bleSetScanFilterDeviceName(filters[ 'include_device_name']) else: self.log.debug( "Setting advertisement include_device_name to False") self.adv_ad.droid.bleSetAdvertiseDataIncludeDeviceName(False) if ('include_tx_power_level' in filters.keys() and filters[ 'include_tx_power_level'] is not False): self.log.debug( "Setting advertisement include_tx_power_level to True") self.adv_ad.droid.bleSetAdvertiseDataIncludeTxPowerLevel(True) if 'manufacturer_specific_data_id' in filters.keys(): if 'manufacturer_specific_data_mask' in filters.keys(): self.adv_ad.droid.bleAddAdvertiseDataManufacturerId( filters['manufacturer_specific_data_id'], filters['manufacturer_specific_data']) self.scn_ad.droid.bleSetScanFilterManufacturerData( filters['manufacturer_specific_data_id'], filters['manufacturer_specific_data'], filters['manufacturer_specific_data_mask']) else: self.adv_ad.droid.bleAddAdvertiseDataManufacturerId( filters['manufacturer_specific_data_id'], filters['manufacturer_specific_data']) self.scn_ad.droid.bleSetScanFilterManufacturerData( filters['manufacturer_specific_data_id'], filters['manufacturer_specific_data']) if 'service_data' in filters.keys(): self.adv_ad.droid.bleAddAdvertiseDataServiceData( filters['service_data_uuid'], filters['service_data']) self.scn_ad.droid.bleSetScanFilterServiceData( filters['service_data_uuid'], filters['service_data']) if 'manufacturer_specific_data_list' in filters.keys(): for pair in filters['manufacturer_specific_data_list']: (manu_id, manu_data) = pair self.adv_ad.droid.bleAddAdvertiseDataManufacturerId(manu_id, manu_data) if 'service_mask' in filters.keys(): self.scn_ad.droid.bleSetScanFilterServiceUuid( filters['service_uuid'].upper(), filters['service_mask']) self.adv_ad.droid.bleSetAdvertiseDataSetServiceUuids([filters[ 'service_uuid'].upper()]) elif 'service_uuid' in filters.keys(): self.scn_ad.droid.bleSetScanFilterServiceUuid(filters[ 'service_uuid']) self.adv_ad.droid.bleSetAdvertiseDataSetServiceUuids([filters[ 'service_uuid']]) self.scn_ad.droid.bleBuildScanFilter(filter_list) advertise_callback, advertise_data, advertise_settings = ( generate_ble_advertise_objects(self.adv_ad.droid)) if ('scan_mode' in settings_in_effect and settings_in_effect['scan_mode'] != ScanSettingsScanMode.SCAN_MODE_OPPORTUNISTIC.value): self.scn_ad.droid.bleSetScanSettingsScanMode(settings_in_effect[ 'scan_mode']) else: self.scn_ad.droid.bleSetScanSettingsScanMode( ScanSettingsScanMode.SCAN_MODE_LOW_LATENCY.value) scan_settings = self.scn_ad.droid.bleBuildScanSetting() scan_callback = self.scn_ad.droid.bleGenScanCallback() self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, scan_callback) opportunistic = False scan_settings2, scan_callback2 = None, None if ('scan_mode' in settings_in_effect and settings_in_effect['scan_mode'] == ScanSettingsScanMode.SCAN_MODE_OPPORTUNISTIC.value): opportunistic = True scan_settings2 = self.scn_ad.droid.bleBuildScanSetting() scan_callback2 = self.scn_ad.droid.bleGenScanCallback() self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings2, scan_callback2) self.scn_ad.droid.bleSetScanSettingsScanMode( ScanSettingsScanMode.SCAN_MODE_OPPORTUNISTIC.value) self.adv_ad.droid.bleStartBleAdvertising( advertise_callback, advertise_data, advertise_settings) expected_advertise_event_name = adv_succ.format(advertise_callback) self.log.debug(expected_advertise_event_name) try: event = self.adv_ad.ed.pop_event(expected_advertise_event_name, self.default_timeout) except Empty: self.log.error("Failed to start advertisement.") return False if not self._bleadvertise_verify_onsuccess(event, settings_in_effect): return False expected_scan_event_name = scan_result.format(scan_callback) try: event = self.scn_ad.ed.pop_event(expected_scan_event_name, self.default_timeout) except Empty: self.log.error("Scan event not found: {}".format(expected_scan_event_name)) return False if not self._blescan_verify_onscanresult_event(event, filters): return False if opportunistic: expected_scan_event_name = scan_result.format(scan_callback2) try: event = self.scn_ad.ed.pop_event(expected_scan_event_name, self.default_timeout) except Empty: self.log.error("Opportunistic scan event not found: {}".format(expected_scan_event_name)) return False if not self._blescan_verify_onscanresult_event(event, filters): return False self.scn_ad.droid.bleStopBleScan(scan_callback2) self.adv_ad.droid.bleStopBleAdvertising(advertise_callback) self.scn_ad.droid.bleStopBleScan(scan_callback) return test_result
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.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
def test_opportunistic_scan_filter_result_off_secondary_scan_result(self): """Test opportunistic scan from a secondary scan result. Tests opportunistic scan where the scan filters are the same between the first scan instance with opportunistic scan set and the second instance with any other mode set. Steps: 1. Initialize advertiser and start advertisement on dut1 2. On dut0, set the scan settings mode to opportunistic scan and set the scan filter device name to the advertiser's device name 3. Start scan scan from step 2 4. Try to find an event, expect none 5. Start a second scanner on dut0, with any other mode set and set the scan filter device name to the advertiser's device name 6. Pop onScanResults from the second scanner 7. Pop onScanResults from the first scanner Expected Result: Opportunistic scan instance finds a advertisement. Returns: Pass if True Fail if False TAGS: LE, Advertising, Scanning, Opportunistic Scan Priority: 1 """ self.adv_ad.droid.bleSetAdvertiseDataIncludeDeviceName(True) self._setup_generic_advertisement() adv_device_name = self.adv_ad.droid.bluetoothGetLocalName() self.scn_ad.droid.bleSetScanSettingsScanMode( ScanSettingsScanMode.SCAN_MODE_OPPORTUNISTIC.value) self.scn_ad.droid.bleSetScanFilterDeviceName(adv_device_name) filter_list, scan_settings, scan_callback = generate_ble_scan_objects( self.scn_ad.droid) self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, scan_callback) self.active_scan_callback_list.append(scan_callback) if not self._verify_no_events_found(scan_result.format(scan_callback)): return False self.scn_ad.droid.bleSetScanSettingsScanMode( ScanSettingsScanMode.SCAN_MODE_LOW_LATENCY.value) filter_list2, scan_settings2, scan_callback2 = ( generate_ble_scan_objects(self.scn_ad.droid)) self.scn_ad.droid.bleSetScanFilterDeviceName(adv_device_name) self.scn_ad.droid.bleBuildScanFilter(filter_list2) self.scn_ad.droid.bleStartBleScan(filter_list2, scan_settings2, scan_callback2) self.active_scan_callback_list.append(scan_callback2) try: self.scn_ad.ed.pop_event(scan_result.format(scan_callback2), self.default_timeout) except Empty: self.log.error("Opportunistic scan found no scan results.") return False try: self.scn_ad.ed.pop_event(scan_result.format(scan_callback), self.default_timeout) except Empty: self.log.error("Non-Opportunistic scan found no scan results.") return False return True
def test_scan_filter_device_address(self): """Test scan filtering of a device address. This test will have to create two scanning instances. The first will have no filters and will find the generic advertisement's mac address. The second will have a filter of the found mac address. Steps: 1. Start a generic advertisement. 2. Start a generic scanner. 3. Find the advertisement and extract the mac address. 4. Stop the first scanner. 5. Create a new scanner with scan filter with a mac address filter of what was found in step 3. 6. Start the scanner. Expected Result: Verify that the advertisement was found in the second scan instance. Returns: Pass if True Fail if False TAGS: LE, Advertising, Filtering, Scanning Priority: 1 """ test_result = True self.scn_ad.droid.bleSetScanSettingsScanMode( ScanSettingsScanMode.SCAN_MODE_LOW_LATENCY.value) filter_list, scan_settings, scan_callback = generate_ble_scan_objects( self.scn_ad.droid) expected_event_name = scan_result.format(scan_callback) self.adv_ad.droid.bleSetAdvertiseSettingsAdvertiseMode( AdvertiseSettingsAdvertiseMode.ADVERTISE_MODE_LOW_LATENCY.value) 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) self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, scan_callback) event_info = self.scn_ad.ed.pop_event(expected_event_name, self.default_timeout) mac_address = event_info['data']['Result']['deviceInfo']['address'] self.log.info( "Filter advertisement with address {}".format(mac_address)) self.scn_ad.droid.bleStopBleScan(scan_callback) self.scn_ad.droid.bleSetScanSettingsScanMode( ScanSettingsScanMode.SCAN_MODE_LOW_LATENCY.value) self.scn_ad.droid.bleSetScanFilterDeviceAddress(mac_address) filter_list2, scan_settings2, scan_callback2 = ( generate_ble_scan_objects(self.scn_ad.droid)) self.scn_ad.droid.bleBuildScanFilter(filter_list2) self.scn_ad.droid.bleStartBleScan(filter_list2, scan_settings2, scan_callback2) expected_event_name = scan_result.format(scan_callback2) found_event = self.scn_ad.ed.pop_event(expected_event_name, self.default_timeout) if (found_event['data']['Result']['deviceInfo']['address'] != mac_address): test_result = False self.scn_ad.droid.bleStopBleScan(scan_callback2) self.adv_ad.droid.bleStopBleAdvertising(advertise_callback) return test_result
def test_filter_manufacturer_id_bounds(self): """Test scan filtering of lower and upper bounds of allowed manu data This test will setup one Android device as an advertiser and the second as the scanner and test the upper and lower bounds of manufacturer data filtering Steps: 1. Start an advertisement with manufacturer id set to 0x004c 2. Start a generic scanner. 3. Find the advertisement and extract the mac address. 4. Stop the first scanner. 5. Create a new scanner with scan filter with a mac address filter of what was found in step 3. 6. Start the scanner. Expected Result: Verify that the advertisement was found in the second scan instance. Returns: Pass if True Fail if False TAGS: LE, Advertising, Filtering, Scanning Priority: 1 """ manufacturer_id_list = [0, 1, 65534, 65535] for manufacturer_id in manufacturer_id_list: self.adv_ad.droid.bleAddAdvertiseDataManufacturerId( manufacturer_id, [0x01]) self.adv_ad.droid.bleSetAdvertiseSettingsAdvertiseMode( AdvertiseSettingsAdvertiseMode.ADVERTISE_MODE_LOW_LATENCY.value ) 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) expected_event = adv_succ.format(advertise_callback) try: self.adv_ad.ed.pop_event(expected_event) except Empty: self.log.info("Failed to start advertisement.") return False self.scn_ad.droid.bleSetScanSettingsScanMode( ScanSettingsScanMode.SCAN_MODE_LOW_LATENCY.value) self.scn_ad.droid.bleSetScanFilterManufacturerData( manufacturer_id, [0x01]) filter_list = self.scn_ad.droid.bleGenFilterList() scan_settings = self.scn_ad.droid.bleBuildScanSetting() scan_filter = self.scn_ad.droid.bleBuildScanFilter(filter_list) scan_callback = self.scn_ad.droid.bleGenScanCallback() self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, scan_callback) expected_event_name = scan_result.format(scan_callback) event = None try: event = self.scn_ad.ed.pop_event(expected_event_name, self.default_timeout) except Empty: self.log.error("Unable to find beacon advertisement.") return False found_manufacturer_id = json.loads( event['data']['Result']['manufacturerIdList']) if found_manufacturer_id[0] != manufacturer_id: self.log.error( "Manufacturer id mismatch. Found {}, Expected {}".format( found_manufacturer_id, manufacturer_id)) return False self.scn_ad.droid.bleStopBleScan(scan_callback) self.adv_ad.droid.bleStopBleAdvertising(advertise_callback) return True
def test_onlost_onfound_defaults(self): """Test generic onlost/onfound defaults. Tests basic onFound/onLost functionality. Steps: 1. Setup dut0 scanner and start scan with this setup: Scan Mode: SCAN_MODE_LOW_LATENCY Callback Type: CALLBACK_TYPE_FOUND_AND_LOST Match Mode: AGGRESSIVE Num of Matches: MATCH_NUM_ONE_ADVERTISEMENT Filter: Device name of dut1 2. Start an advertisement on dut1, include device name 3. Find an onFound event 4. Stop the advertisement on dut1 5. Find an onLost event Expected Result: Find an onLost and an onFound event successfully. Returns: Pass if True Fail if False TAGS: LE, Advertising, Scanning, onLost, onFound Priority: 0 """ filter_list = self.scn_ad.droid.bleGenFilterList() self.scn_ad.droid.bleSetScanFilterDeviceName( self.adv_ad.droid.bluetoothGetLocalName()) self.scn_ad.droid.bleSetScanSettingsScanMode( ScanSettingsScanMode.SCAN_MODE_LOW_LATENCY.value) self.scn_ad.droid.bleSetScanSettingsCallbackType( ScanSettingsCallbackType.CALLBACK_TYPE_FOUND_AND_LOST.value) self.scn_ad.droid.bleSetScanSettingsMatchMode( ScanSettingsMatchMode.AGGRESIVE.value) self.scn_ad.droid.bleSetScanSettingsNumOfMatches( ScanSettingsMatchNum.MATCH_NUM_ONE_ADVERTISEMENT.value) scan_settings = self.scn_ad.droid.bleBuildScanSetting() scan_callback = self.scn_ad.droid.bleGenScanCallback() self.scn_ad.droid.bleBuildScanFilter(filter_list) self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, scan_callback) self.active_scan_callback_list.append(scan_callback) adv_callback = self._start_generic_advertisement_include_device_name() event = self.scn_ad.ed.pop_event(scan_result.format(scan_callback), self.default_timeout * 3) found_callback_type = event['data']['CallbackType'] if event['data'][ 'CallbackType'] != ScanSettingsCallbackType.CALLBACK_TYPE_FIRST_MATCH.value: self.log.info( "Found Callbacreset_bluetoothkType:{}, Expected CallbackType:{}" .format( found_callback_type, ScanSettingsCallbackType.CALLBACK_TYPE_FIRST_MATCH.value)) return False self.adv_ad.droid.bleStopBleAdvertising(adv_callback) event = self.scn_ad.ed.pop_event(scan_result.format(scan_callback), self.default_timeout * 4) found_callback_type = event['data']['CallbackType'] if found_callback_type != ScanSettingsCallbackType.CALLBACK_TYPE_MATCH_LOST.value: self.log.info( "Found CallbackType:{}, Expected CallbackType:{}".format( found_callback_type, ScanSettingsCallbackType.CALLBACK_TYPE_MATCH_LOST.value)) return False return True