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( ble_scan_settings_modes['opportunistic']) 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( ble_scan_settings_modes['low_latency']) 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_batch_scan_result_not_expected(self): """Test opportunistic batch scan without expecting an event. Tests opportunistic scan where it will only report scan results when other registered scanners find results. Set the report delay millis such that a batch scan is not expected. Steps: 1. Initialize advertiser and start advertisement on dut1 2. Initialize scanner with scan mode set to opportunistic mode and set scan settings report delay seconds such that a batch scan is expected. 3. Start scanning on dut 0 4. Try to find an event, expect none. 5. Start a second scanner on dut0, with any other mode set and set scan settings report delay millis to 0 such that an onBatchScanResult is not expected. 6. Pop onScanResults event on the second scanner 7. Pop onBatchScanResult event on the first scanner Expected Result: Batch scan result is not expected on opportunistic scan instance. Returns: Pass if True Fail if False TAGS: LE, Advertising, Scanning, Opportunistic Scan, Batch Scanning Priority: 1 """ self._setup_generic_advertisement() self.scn_ad.droid.bleSetScanSettingsScanMode( ble_scan_settings_modes['opportunistic']) self.scn_ad.droid.bleSetScanSettingsReportDelayMillis( self.report_delay) 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( batch_scan_result.format(scan_callback)): return False self.scn_ad.droid.bleSetScanSettingsScanMode( ble_scan_settings_modes['low_latency']) 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 return self._verify_no_events_found( batch_scan_result.format(scan_callback))
def test_max_opportunistic_batch_scan_instances(self): """Test max opportunistic batch scan instances. Tests max instances of opportunistic batch scans. Each instances should find an onBatchScanResult event. Steps: 1. Initialize advertiser and start advertisement on dut1 2. Set scan settings to opportunistic scan on dut0 scan instance and set report delay seconds such that an onBatchScanResult is expected 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 onBatchScanResult event on all scan instances Expected Result: Each opportunistic scan instance finds an advertisement. Returns: Pass if True Fail if False TAGS: LE, Advertising, Scanning, Opportunistic Scan, Batch Scanning Priority: 1 """ self._setup_generic_advertisement() for _ in range(self.max_scan_instances - 1): self.scn_ad.droid.bleSetScanSettingsScanMode( ble_scan_settings_modes['opportunistic']) self.scn_ad.droid.bleSetScanSettingsReportDelayMillis( self.report_delay) 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( ble_scan_settings_modes['low_latency']) self.scn_ad.droid.bleSetScanSettingsReportDelayMillis( self.report_delay) 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(batch_scan_result.format(callback), self.default_timeout) except Empty: self.log.error( "No scan results found for callback {}".format(callback)) return True
def test_negative_opportunistic_scan_filter_result_off_secondary_scan_result( self): """Test opportunistic scan not found scenario. Tests opportunistic scan where the secondary scan instance does find an advertisement but the scan instance with scan mode set to opportunistic scan does not find an advertisement due to mismatched scan filters. 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 and set the scan filter device name to "opp_test" 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 6. Pop onScanResults from the second scanner 7. Pop onScanResults from the first scanner 8. Expect no events Expected Result: Opportunistic scan instance doesn't find any advertisements. 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) self.scn_ad.droid.bleSetScanFilterDeviceName("opp_test") 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) 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 return self._verify_no_events_found(scan_result.format(scan_callback))
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( ble_scan_settings_modes['opportunistic']) 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( ble_scan_settings_modes['low_latency']) 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_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_loop_scanning_1000(self): """Stress start/stop scan instances. This test will start and stop scan instances as fast as possible. This will guarantee that the scan instances are properly being cleaned up when the scan is stopped. Steps: 1. Start a scan instance. 2. Stop the scan instance. 3. Repeat steps 1-2 1000 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 """ test_result = True for _ in range(1000): 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.scn_ad.droid.bleStopBleScan(scan_callback) return test_result
def ble_start_stop_scan(self): """Convenience method to start BLE scan and stop BLE scan. Steps: 1. Enable ble. 2. Create LE scan objects. 3. Start scan. 4. Stop scan. Returns: True if successful, False otherwise. """ for i in self.attenuation_range: self.pri_ad.droid.bluetoothEnableBLE() filter_list, scan_settings, scan_callback = generate_ble_scan_objects( self.pri_ad.droid) self.pri_ad.droid.bleStartBleScan(filter_list, scan_settings, scan_callback) time.sleep(self.iperf["duration"]) try: self.pri_ad.droid.bleStopBleScan(scan_callback) except Exception as err: self.log.error(str(err)) 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( ble_scan_settings_modes['opportunistic']) 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_anonymous_advertising(self): """Test anonymous advertising. Tests test verify that device is able to receive anonymous advertising on 1M PHY when secondary is 2M PHY. Steps: 1. Start anonymous advertising set on dut1 2. Start scanning on dut0, scan filter set to advertiser's device name 3. Try to find an event, expect found 4. Stop advertising Expected Result: Scan finds a advertisement. Returns: Pass if True Fail if False TAGS: LE Advertising Extension, BT5, LE, Advertising, Scanning Priority: 1 """ adv_callback = self.adv_ad.droid.bleAdvSetGenCallback() self.adv_ad.droid.bleAdvSetStartAdvertisingSet({ "connectable": False, "anonymous": True, "legacyMode": False, "primaryPhy": "PHY_LE_1M", "secondaryPhy": "PHY_LE_2M", "interval": 320 }, self.big_adv_data, None, None, None, 0, 0, adv_callback) self.scn_ad.droid.bleSetScanSettingsLegacy(False) self.scn_ad.droid.bleSetScanSettingsPhy(ble_scan_settings_phys['1m']) filter_list, scan_settings, scan_callback = generate_ble_scan_objects( self.scn_ad.droid) adv_device_name = self.adv_ad.droid.bluetoothGetLocalName() self.scn_ad.droid.bleSetScanFilterDeviceName(adv_device_name) 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) try: evt = self.scn_ad.ed.pop_event( scan_result.format(scan_callback), self.default_timeout) address = evt['data']['Result']['deviceInfo']['address'] asserts.assert_true( '00:00:00:00:00:00' == address, "Anonymous address should be 00:00:00:00:00:00, but was " + str(address)) except Empty: self.log.error("Scan result not found") self.adv_ad.droid.bleAdvSetStopAdvertisingSet(adv_callback) return False self.adv_ad.droid.bleAdvSetStopAdvertisingSet(adv_callback) return True
def test_restart_scan_callback_after_bt_toggle(self): """Test to reuse an scan callback. This will verify if scan objects can be reused after a bluetooth toggle. Steps: 1. Start a scanning instance. 3. Stop the scanning instance. 4. Toggle bluetooth off and on. 5. Start an scanning instance on the same objects used in step 1. Expected Result: Scanner should start successfully. Returns: Pass if True Fail if False TAGS: LE, Scanning, Stress Priority: 1 """ test_result = True 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) reset_bluetooth([self.scn_ad]) self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, scan_callback) return test_result
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.scn_ad.droid.bleSetScanFilterServiceUuid(service_uuid, service_mask) self.adv_ad.droid.bleSetAdvertiseSettingsAdvertiseMode( ble_advertise_settings_modes['low_latency']) 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.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.bleSetScanFilterDeviceName( self.adv_ad.droid.bluetoothGetLocalName()) self.scn_ad.droid.bleBuildScanFilter(filter_list) 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_legacy_scan_result_raw_length(self): """Test that raw scan record data in legacy scan is 62 bytes long. This is required for compability with older apps that make this assumption. Steps: 1. Start legacy advertising set on dut1 2. Start scanning on dut0, scan filter set to advertiser's device name 3. Try to find an event, expect found, verify scan recurd data length 4. Stop advertising Expected Result: Scan finds a legacy advertisement of proper size Returns: Pass if True Fail if False TAGS: LE Advertising Extension, BT5, LE, Advertising, Scanning Priority: 1 """ adv_callback = self.adv_ad.droid.bleAdvSetGenCallback() self.adv_ad.droid.bleAdvSetStartAdvertisingSet( { "connectable": True, "scannable": True, "legacyMode": True, "interval": 320 }, {"includeDeviceName": True}, None, None, None, 0, 0, adv_callback) self.scn_ad.droid.bleSetScanSettingsLegacy(True) self.scn_ad.droid.bleSetScanSettingsPhy(ble_scan_settings_phys['1m']) filter_list, scan_settings, scan_callback = generate_ble_scan_objects( self.scn_ad.droid) adv_device_name = self.adv_ad.droid.bluetoothGetLocalName() self.scn_ad.droid.bleSetScanFilterDeviceName(adv_device_name) 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) try: evt = self.scn_ad.ed.pop_event(scan_result.format(scan_callback), self.default_timeout) rawData = evt['data']['Result']['scanRecord'] asserts.assert_true(62 == len(rawData.split(",")), "Raw data should be 62 bytes long.") except Empty: self.log.error("Scan result not found") self.adv_ad.droid.bleAdvSetStopAdvertisingSet(adv_callback) return False self.adv_ad.droid.bleAdvSetStopAdvertisingSet(adv_callback) return True
def test_scan_trigger_on_batch_scan_results(self): """Test triggering batch scan results. Test that triggers onBatchScanResults and verifies the time to trigger within one second leeway. Steps: 1. Setup the scanning android device with report delay seconds set to 5000. 2. Setup the advertiser android devices. 3. Verify that only one onBatchScanResult callback was triggered. 4. Compare the system time that the scan was started with the elapsed time that is in the callback. Expected Result: The scan event dispatcher should find an onBatchScanResult event. Returns: Pass if True Fail if False TAGS: LE, Advertising, Filtering, Scanning, Batch Scanning Priority: 2 """ test_result = True self.scn_ad.droid.bleSetScanSettingsReportDelayMillis(5000) filter_list, scan_settings, scan_callback = generate_ble_scan_objects( self.scn_ad.droid) expected_event_name = batch_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.bleSetScanFilterDeviceName( self.adv_ad.droid.bluetoothGetLocalName()) self.scn_ad.droid.bleBuildScanFilter(filter_list) self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, scan_callback) system_time_nanos = self.scn_ad.droid.getSystemElapsedRealtimeNanos() self.log.debug("Current system time: {}".format(system_time_nanos)) worker = self.scn_ad.ed.handle_event( self.blescan_verify_onbatchscanresult_event_handler, expected_event_name, ([system_time_nanos, 5000000000]), 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: {}".format(error)) except concurrent.futures._base.TimeoutError as error: test_result = False self.log.debug("Test failed with: {}".format(error)) 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_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.bleSetAdvertiseDataIncludeDeviceName(True) self.adv_ad.droid.bleSetAdvertiseSettingsAdvertiseMode( ble_advertise_settings_modes['low_latency']) 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.bleSetScanFilterDeviceName( self.adv_ad.droid.bluetoothGetLocalName()) self.scn_ad.droid.bleBuildScanFilter(filter_list) 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.error("Test failed with Empty error: {}".format(error)) except concurrent.futures._base.TimeoutError as error: test_result = False self.log.error("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_background_scan_ble_disabled(self): """Test background LE scanning with LE disabled. 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 """ self._setup_generic_advertisement() self.scn_ad.droid.bluetoothEnableBLE() self.scn_ad.droid.bleSetScanSettingsScanMode( ble_scan_settings_modes['low_latency']) filter_list, scan_settings, scan_callback = generate_ble_scan_objects( self.scn_ad.droid) self.scn_ad.droid.bleSetScanFilterDeviceName( self.adv_ad.droid.bluetoothGetLocalName()) self.scn_ad.droid.bleBuildScanFilter(filter_list) self.scn_ad.droid.bluetoothToggleState(False) try: self.scn_ad.ed.pop_event(bluetooth_off, self.default_timeout) except Empty: self.log.info(self.scn_ad.droid.bluetoothCheckState()) self.log.error("Bluetooth Off event not found. Expected {}".format( bluetooth_off)) return False try: 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 except Exception: self.log.info( "Was not able to start a background scan as expected.") return True
def test_gatt_connect_stress(self): """Test the round trip speed of connecting to a peripheral many times This test will prompt the user to press "Enter" when the peripheral is in a connecable advertisement state. Once the user presses enter, this script will measure the amount of time it takes to establish a GATT connection to the peripheral. The test will then disconnect. It will attempt to repeat this process multiple times. Steps: 1. Wait for user input to confirm peripheral is advertising. 2. Start timer 3. Perform GATT connection to peripheral 4. Upon successful connection, stop timer 5. Disconnect from peripheral 6. Repeat steps 2-5 1000 times. Expected Result: Test should measure 1000 iterations of connect/disconnect cycles. Returns: Pass if True Fail if False TAGS: LE, GATT Priority: 2 """ 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) self.AUTOCONNECT = False iterations = 1000 n = 0 while n < iterations: self.start_timer() try: bluetooth_gatt, gatt_callback = (setup_gatt_connection( self.cen_ad, self.ble_mac_address, self.AUTOCONNECT, gatt_transport['le'])) except GattTestUtilsError as err: self.log.error(err) return False self.log.info("Total time (ms): {}".format(self.end_timer())) try: disconnect_gatt_connection(self.cen_ad, bluetooth_gatt, gatt_callback) self.cen_ad.droid.gattClientClose(bluetooth_gatt) except GattTestUtilsError as err: self.log.error(err) return False n += 1 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_duration(self): """Test scanning duration Tests BT5.0 scanning duration Steps: 1. Start advertising set 2. Start 5.0 scan 3. Scan for advertisement event Expected Result: Scan finds a legacy advertisement of proper size Returns: Pass if True Fail if False TAGS: BT5.0, LE, Advertising, Scanning Priority: 1 """ adv_callback = self.adv_ad.droid.bleAdvSetGenCallback() self.adv_ad.droid.bleAdvSetStartAdvertisingSet( { "connectable": True, "legacyMode": False, "primaryPhy": "PHY_LE_1M", "secondaryPhy": "PHY_LE_2M", "interval": 320 }, self.big_adv_data, None, None, None, 0, 0, adv_callback) self.scn_ad.droid.bleSetScanSettingsLegacy(False) self.scn_ad.droid.bleSetScanSettingsPhy(ble_scan_settings_phys['1m']) filter_list, scan_settings, scan_callback = generate_ble_scan_objects( self.scn_ad.droid) adv_device_name = self.adv_ad.droid.bluetoothGetLocalName() self.scn_ad.droid.bleSetScanFilterDeviceName(adv_device_name) 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) try: self.scn_ad.ed.pop_event(scan_result.format(scan_callback), self.default_timeout) except Empty: self.log.error("Scan result not found") self.adv_ad.droid.bleAdvSetStopAdvertisingSet(adv_callback) return False self.adv_ad.droid.bleAdvSetStopAdvertisingSet(adv_callback) return True
def test_scan_flush_results_without_on_batch_scan_results_triggered(self): """Test that doesn't expect a batch scan result. Test flush pending scan results with a report delay seconds set to 0. No onBatchScanResults callback should be triggered. Steps: 1. Setup the scanning android device with report delay seconds set to 0 (or just use default). 2. Setup the advertiser android devices. Expected Result: Verify that no onBatchScanResults were triggered. Returns: Pass if True Fail if False TAGS: LE, Advertising, Filtering, Scanning, Batch Scanning Priority: 2 """ test_result = True filter_list, scan_settings, scan_callback = generate_ble_scan_objects( self.scn_ad.droid) expected_event_name = batch_scan_result.format(scan_callback) 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) self.scn_ad.droid.bleSetScanFilterDeviceName( self.adv_ad.droid.bluetoothGetLocalName()) self.scn_ad.droid.bleBuildScanFilter(filter_list) self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, scan_callback) worker = self.scn_ad.ed.handle_event( self.blescan_verify_onbatchscanresult_event_handler, expected_event_name, ([]), self.default_timeout) self.scn_ad.droid.bleFlushPendingScanResults(scan_callback) try: event_info = self.scn_ad.ed.pop_event(expected_event_name, 10) self.log.debug( "Unexpectedly found an advertiser: {}".format(event_info)) test_result = False except Empty: self.log.debug("No {} events were found as expected.".format( batch_scan_result)) 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_scan_filters_works_with_screen_off(self): """Test LE scanning is successful with filters and screen off. Test LE scanning is successful with no filters and screen off. No scan results should be found. Steps: 1. Setup advertisement 2. Turn off screen 3. Start scanner with filters 4. Verify scan results are found 5. Teardown advertisement and scanner Expected Result: Scan results should be found. Returns: Pass if True Fail if False TAGS: LE, Advertising, Filtering, Scanning, Screen Priority: 1 """ # Step 1 adv_device_name = self.adv_ad.droid.bluetoothGetLocalName() print(adv_device_name) self.adv_ad.droid.bleSetAdvertiseDataIncludeDeviceName(True) if not self._setup_generic_advertisement(): return False # Step 2 self.scn_ad.droid.goToSleepNow() # Step 3 self.scn_ad.droid.bleSetScanFilterDeviceName(adv_device_name) filter_list, scan_settings, self.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, self.scan_callback) # Step 4 if not self._scan_found_results(): return False # Step 5 self.adv_ad.droid.bleStopBleAdvertising(self.advertise_callback) self.scn_ad.droid.bleStopBleScan(self.scan_callback) return True
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 test_swarm_10000_on_batch_scan_result(self): """Test LE batch scanning in a mass beacon deployment. Test finding 10000 LE batch scan results in a mass beacon deployment. Steps: 1. Assume that mass beacon deployment is setup. 2. Set LE scanning mode to low latency and report delay millis to 1 second. 3. Start LE scan. 4. Pop batch scan results off the event dispatcher 10000 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) self.scn_ad.droid.bleSetScanSettingsReportDelayMillis(1000) 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(10000): event_info = self.scn_ad.ed.pop_event( batch_scan_result.format(scan_callback), self.default_timeout) for result in event_info['data']['Results']: mac_address = 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.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_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_batch_scan_result_no_advertisement(self): """Test batch opportunistic scan without an advertisement. Tests opportunistic scan where there are no advertisements. This should not find any onBatchScanResult. Steps: 1. Initialize scanner with scan mode set to opportunistic mode. 2. Set report delay seconds such that onBatchScanResult events are expected 2. Start scanning on dut 0 3. Pop onBatchScanResult 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, Batch Scanning Priority: 1 """ self.scn_ad.droid.bleSetScanSettingsScanMode( ScanSettingsScanMode.SCAN_MODE_OPPORTUNISTIC.value) self.scn_ad.droid.bleSetScanSettingsReportDelayMillis( self.report_delay) 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( batch_scan_result.format(scan_callback)): return False self.scn_ad.droid.bleStopBleScan(scan_callback) return True
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( ble_scan_settings_modes['opportunistic']) 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( ble_scan_settings_modes['low_latency']) 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