1 # Copyright (c) 2013 The Chromium OS Authors. All rights reserved. 2 # Use of this source code is governed by a BSD-style license that can be 3 # found in the LICENSE file. 4 5 import cgi 6 import logging 7 8 from autotest_lib.client.bin import utils 9 from autotest_lib.client.common_lib import error 10 from autotest_lib.server.cros.bluetooth import bluetooth_test 11 12 13 class bluetooth_Sanity_Discovery(bluetooth_test.BluetoothTest): 14 """ 15 Verify that the client can discover the tester. 16 """ 17 version = 1 18 19 # How long should the tester remain discoverable? 20 DISCOVERABLE_TIMEOUT=180 21 22 def find_device(self): 23 """Retrieve devices from client and look for tester. 24 25 @return True if device has been found, False otherwise. 26 27 """ 28 # Get the set of devices known to the DUT. 29 devices = self.device.get_devices() 30 if devices == False: 31 raise error.TestFail('Could not retrieve devices from DUT') 32 33 device_found = False 34 for device in devices: 35 if self.tester: 36 if self.address == device['Address']: 37 logging.info('Found tester with RSSI %d', 38 device.get('RSSI')) 39 # Check name as well; if the name and alias fields don't 40 # match, that means it hasn't been requested yet, so 41 # wait until next time. 42 if device.get('Name') != device['Alias']: 43 logging.info('Device name not yet received') 44 continue 45 if device['Alias'] not in self.name_list: 46 raise error.TestFail( 47 'Tester "%s" is not one of the expected names ' 48 '"%s"' % (device['Alias'], str(self.name_list))) 49 # Found the device 50 device_found = True 51 # Write out the RSSI now we've found it. 52 self.write_perf_keyval({'rssi': int(device.get('RSSI', 0))}) 53 self.output_perf_value('rssi', int(device.get('RSSI', 0)), 54 'dBm') 55 56 if self.interactive: 57 item_name = device['Address'].replace(':', '') 58 html = '%s %s' % (cgi.escape(device['Address']), 59 cgi.escape(device['Alias'])) 60 61 if device['Address'] in self.devices_discovered: 62 self.interactive.replace_list_item(item_name, html) 63 else: 64 self.interactive.append_list_item('devices', item_name, 65 html) 66 self.devices_discovered.append(device['Address']) 67 68 result = self.interactive.check_for_button() 69 if result == 0: 70 device_found = True 71 elif result != -1: 72 raise error.TestFail('User indicated test failed') 73 74 return device_found 75 76 77 def run_once(self): 78 """Running bluetooth test to discover a remote discoverable device.""" 79 # Reset the adapter to the powered on state. 80 if not self.device.reset_on(): 81 raise error.TestFail('DUT could not be reset to initial state') 82 83 if self.tester: 84 # Setup the tester as a generic computer. 85 if not self.tester.setup('computer'): 86 raise error.TestFail('Tester could not be initialized') 87 # Make the tester discoverable 88 self.tester.set_discoverable(True, self.DISCOVERABLE_TIMEOUT) 89 # Read the tester information so we know what we're looking for. 90 ( address, bluetooth_version, manufacturer_id, 91 supported_settings, current_settings, class_of_device, 92 name, short_name ) = self.tester.read_info() 93 self.address = address 94 self.name = name 95 self.name_list = [name, short_name] 96 97 if self.interactive: 98 self.interactive.login() 99 100 if self.tester: 101 self.interactive.append_output( 102 '<p>The Tester is in the discoverable state. ' 103 '<p>The DUT is in the page scan/discovery state. ' 104 '<p>Please verify that you can discover the tester ' + 105 ('<b>%s</b> with address <b>%s</b> from the device.' % 106 (cgi.escape(self.name), 107 cgi.escape(self.address)))) 108 else: 109 self.interactive.append_output( 110 '<p>The DUT is in the page scan/discovery state. ' 111 '<p>Please verify that you can discover the device.') 112 113 self.interactive.append_output('<h2>Devices Found</h2>') 114 self.interactive.append_list('devices') 115 self.devices_discovered = [] 116 117 if self.tester: 118 self.interactive.append_buttons('Tester Found', 119 'Tester Not Found') 120 else: 121 self.interactive.append_buttons('Device Found', 122 'Device Not Found') 123 124 # Discover devices from the DUT. 125 for failed_attempts in range(0, 5): 126 if not self.device.start_discovery(): 127 raise error.TestFail('Could not start discovery on DUT') 128 try: 129 utils.poll_for_condition( 130 condition=self.find_device, 131 desc='Device discovered from DUT', 132 timeout=self.DISCOVERABLE_TIMEOUT) 133 # We only reach this if we find a device. Break out of the 134 # failed_attempts loop to bypass the "reached the end" 135 # condition. 136 break 137 except utils.TimeoutError: 138 # Capture the timeout error and try once more through the 139 # loop. 140 pass 141 finally: 142 if not self.device.stop_discovery(): 143 logging.warning('Failed to stop discovery on DUT') 144 else: 145 # We only reach this if we tried five times to find the device and 146 # failed. 147 raise error.TestFail('DUT could not discover device') 148 # Record how many attempts this took, hopefully we'll one day figure 149 # out a way to reduce this to zero and then the loop above can go 150 # away. 151 self.write_perf_keyval({'failed_attempts': failed_attempts }) 152 self.output_perf_value('failed_attempts', failed_attempts, 'attempts') 153 154 155 def cleanup(self): 156 """Set the tester back to undiscoverable.""" 157 if self.tester: 158 self.tester.set_discoverable(False) 159 160 super(bluetooth_Sanity_Discovery, self).cleanup() 161