def run_once(self, host=None, wifi_iface=None, wifi_ssid=None): """Check that a given wifi interface is properly configured. @param host: a host object representing the DUT. @param wifi_iface: Name of the wifi interface to test; None means we'll try to detect at least one that works. @param wifi_ssid: Name of the SSID we want the interface to be connected to; None means any. @raise TestFail: The test failed. """ err_iface = ('No interface is' if wifi_iface is None else 'Interface %s is not' % wifi_iface) # First check link status and SSID. iw = iw_runner.IwRunner(remote_host=host) active_ifaces = [] try: iw_ifaces = [ iface_tuple.if_name for iface_tuple in iw.list_interfaces() ] if wifi_iface is not None: if wifi_iface not in iw_ifaces: raise error.TestFail('Interface %s not listed by iw' % wifi_iface) test_ifaces = [wifi_iface] else: test_ifaces = iw_ifaces for iface in test_ifaces: iface_ssid = iw.get_link_value(iface, 'SSID') if (iface_ssid is not None and (wifi_ssid is None or iface_ssid == wifi_ssid)): active_ifaces.append(iface) except error.AutoservRunError: raise error.TestFail('Failed to run iw') if not active_ifaces: err_ssid = 'any SSID' if wifi_ssid is None else 'SSID ' + wifi_ssid raise error.TestFail('%s connected to %s' % (err_iface, err_ssid)) logging.info('Active wifi interfaces: %s', ', '.join(active_ifaces)) # Then check IPv4 connectivity. try: ifconfig_output = host.run_output('ifconfig').splitlines() except error.AutoservRunError: raise error.TestFail('Failed to run ifconfig') ifconfig_dict = self.get_ifconfig_dict(ifconfig_output) connected_ifaces = [ iface for iface in active_ifaces if any([ 'inet addr:' in line for line in ifconfig_dict.get(iface, []) ]) ] if not connected_ifaces: raise error.TestFail('%s IPv4 connected' % err_iface) logging.info('IPv4 connected wifi interfaces: %s', ', '.join(connected_ifaces))
def run_once(self): """Body of the test.""" get_assoc_params = lambda conf: xmlrpc_datatypes.AssociationParameters( ssid=self.context.router.get_ssid(instance=0), bgscan_config=conf) get_ping_config = lambda period: ping_runner.PingConfig( self.context.get_wifi_addr(), interval=self.PING_INTERVAL_SECONDS, count=int(period / self.PING_INTERVAL_SECONDS)) self.context.configure(self._config_first_ap) bgscan_config = xmlrpc_datatypes.BgscanConfiguration( short_interval=self.CONFIGURED_BGSCAN_INTERVAL_SECONDS, long_interval=self.CONFIGURED_BGSCAN_INTERVAL_SECONDS, method=xmlrpc_datatypes.BgscanConfiguration.SCAN_METHOD_SIMPLE) self.context.assert_connect_wifi(get_assoc_params(bgscan_config)) logging.info('Pinging router with background scans for %d seconds.', self.BGSCAN_SAMPLE_PERIOD_SECONDS) result_bgscan = self.context.client.ping( get_ping_config(self.BGSCAN_SAMPLE_PERIOD_SECONDS)) logging.info('Ping statistics with bgscan: %r', result_bgscan) # Bring up a second AP, make sure that it shows up in bgscans. self._config_second_ap.ssid = self.context.router.get_ssid() self.context.configure(self._config_second_ap, multi_interface=True) logging.info('Without a ping running, ensure that bgscans succeed.') ap_mac = self.context.router.get_hostapd_mac(ap_num=1) logging.debug('Looking for BSS %s', ap_mac) iw = iw_runner.IwRunner(remote_host=self.context.client.host) utils.poll_for_condition( condition=lambda: self._find_bss_matching_mac_addr(iw, ap_mac), exception=error.TestFail( 'Background scans should detect new BSSes ' 'within an associated ESS.'), timeout=self.BGSCAN_SAMPLE_PERIOD_SECONDS, sleep_interval=1) self.context.router.deconfig_aps(instance=1) self.context.client.shill.disconnect( self.context.router.get_ssid(instance=0)) # Reconfigure AP, so the new bgscan setting can be correctly applied. self.context.configure(self._config_first_ap) # Gather some statistics about ping latencies without scanning going on. self.context.assert_connect_wifi(get_assoc_params(None)) logging.info('Pinging router without background scans for %d seconds.', self.NO_BGSCAN_SAMPLE_PERIOD_SECONDS) result_no_bgscan = self.context.client.ping( get_ping_config(self.NO_BGSCAN_SAMPLE_PERIOD_SECONDS)) logging.info('Ping statistics without bgscan: %r', result_no_bgscan) if result_no_bgscan.max_latency > self.THRESHOLD_BASELINE_LATENCY_MS: raise error.TestFail('RTT latency is too high even without ' 'background scans: %f' % result_no_bgscan.max_latency) if (result_bgscan.max_latency > self.LATENCY_MARGIN_MS + result_no_bgscan.avg_latency): raise error.TestFail( 'Significant difference in rtt due to bgscan: ' '%.1f > %.1f + %d' % (result_bgscan.max_latency, result_no_bgscan.avg_latency, self.LATENCY_MARGIN_MS))
def prepare_work_client(self, work_client_machine): """Prepare the SSHHost object into WiFiClient object @param work_client_machine: a SSHHost object to be wrapped """ work_client_host = hosts.create_host(work_client_machine.hostname) # All packet captures in chaos lab have dual NICs. Let us use phy1 to # be a radio dedicated for work client iw = iw_runner.IwRunner(remote_host=work_client_host) phys = iw.list_phys() devs = iw.list_interfaces(desired_if_type='managed') if len(devs) > 0: logging.debug('Removing interfaces in work host machine %s', devs) for i in range(len(devs)): iw.remove_interface(devs[i].if_name) if len(phys) > 1: logging.debug('Adding interfaces in work host machine') iw.add_interface('phy1', 'work0', 'managed') logging.debug('Interfaces in work client %s', iw.list_interfaces()) elif len(phys) == 1: raise error.TestError('Not enough phys available to create a' 'work client interface %s.' % work_client_host.hostname) self.work_client = wifi_client.WiFiClient( work_client_host, './debug', False) # Make the host object easily accessible self.host = self.work_client.host
def get_highest_mcs_rate(self, frequency): """ Get the highest MCS index supported by the DUT on |frequency|. @param frequency: int frequency to look for supported MCS rates. @return int highest rate supported. """ # Figure out the highest MCS index supported by this hardware. phys = iw_runner.IwRunner( remote_host=self.context.client.host).list_phys() if len(phys) != 1: raise error.TestFail('Test expects a single PHY, but we got %d' % len(phys)) phy = phys[0] bands = [band for band in phy.bands if frequency in band.frequencies] if len(bands) != 1: raise error.TestFail('Test expects a single possible band for a ' 'given frequency, but this device has %d ' 'such bands.' % len(bands)) # 32 is a special low throughput, high resilience mode. Ignore it. possible_indices = filter(lambda x: x != 32, bands[0].mcs_indices) if not possible_indices: raise error.TestFail('No possible MCS indices on frequency %d' % frequency) return max(possible_indices)
def count_mismatched_phy_configs(cls, dut_host, expected_channel_configs): """Verifies that phys on the DUT place the expected restrictions on channels. Compares the restrictions reported by the running system to the restrictions in |expected_channel_configs|. Returns a count of the number of mismatches. Note that this method deliberately ignores channels that are reported by the running system, but not mentioned in |expected_channel_configs|. This allows us to program the control file with "spot checks", rather than an exhaustive list of channels. @param dut_host The host object for the DUT. @param expected_channel_configs A channel_infos list. @return int count of mismatches """ actual_channel_expectations = cls.phy_list_to_channel_expectations( iw_runner.IwRunner(dut_host).list_phys()) mismatches = 0 for expected_config in expected_channel_configs: channel = expected_config['chnum'] expected = expected_config['expect'] actual = actual_channel_expectations[channel] if actual != expected: logging.error( 'Expected phy config for channel %d of |%s|, but got |%s|.', channel, expected, actual) mismatches += 1 return mismatches
def test_station_link_key(self): """Test a link key is extracted from station link information.""" host = self.host(self.STATION_LINK_INFORMATION) runner = iw_runner.IwRunner(remote_host=host) self.assertEquals( runner.get_link_value(self.STATION_LINK_INFORMATION, iw_runner.IW_LINK_KEY_FREQUENCY), self.STATION_LINK_FREQ)
def test_multiple_ssids(self): """Test with multiple networks with the same ssids.""" scan_output = self.HT40_ABOVE + self.HT20 + self.NO_HT + self.HT20_2 host = self.host(scan_output + self.SCAN_TIME_OUTPUT) runner = iw_runner.IwRunner(remote_host=host) networks = runner.wait_for_scan_result('wlan 0', ssids=[self.HT20_2_IW_BSS.ssid]) for iw_bss_1, iw_bss_2 in zip([self.HT20_IW_BSS, self.HT20_2_IW_BSS], networks): self.verify_values(iw_bss_1, iw_bss_2)
def search_by_bss(self, scan_output, test_iw_bss): """ @param scan_output: the output of the scan as a string @param test_iw_bss: an IWBss object Uses the runner to search for a network by bss. """ host = self.host(scan_output + self.SCAN_TIME_OUTPUT) runner = iw_runner.IwRunner(remote_host=host) network = runner.wait_for_scan_result('wlan0', bsses=[test_iw_bss.bss]) self.verify_values(test_iw_bss, network[0])
def dut_sees_bss(self, bssid): """ Check if a DUT can see a BSS in scan results. @param bssid: string bssid of AP we expect to see in scan results. @return True iff scan results from DUT include the specified BSS. """ runner = iw_runner.IwRunner(remote_host=self.context.client.host) is_requested_bss = lambda iw_bss: iw_bss.bss == bssid scan_results = runner.scan(self.context.client.wifi_if) return scan_results and filter(is_requested_bss, scan_results)
def run_once(self): """Test main loop""" self._iw = iw_runner.IwRunner() initial_regdomain = self._iw.get_regulatory_domain() logging.info('Initial regulatory domain is %s', initial_regdomain) domain_list = self.get_regulatory_domains() if not domain_list: raise error.TestFail('Did not get a domain list from the database') for domain in domain_list: self.assert_set_regulatory_domain(domain) self.assert_set_regulatory_domain(initial_regdomain)
def __setup(self): """Set up this system. Can be used either to complete initialization of a LinuxSystem object, or to re-establish a good state after a reboot. """ # Command locations. cmd_iw = path_utils.must_be_installed('/usr/sbin/iw', host=self.host) self.cmd_ip = path_utils.must_be_installed('/usr/sbin/ip', host=self.host) self.cmd_readlink = '%s -l' % path_utils.must_be_installed( '/bin/ls', host=self.host) self._packet_capturer = packet_capturer.get_packet_capturer( self.host, host_description=self.role, cmd_ip=self.cmd_ip, cmd_iw=cmd_iw, ignore_failures=True) self.iw_runner = iw_runner.IwRunner(remote_host=self.host, command_iw=cmd_iw) self._phy_list = None self.phys_for_frequency, self.phy_bus_type = self._get_phy_info() logging.debug('Current regulatory domain %r', self.iw_runner.get_regulatory_domain()) self._interfaces = [] self._brif_index = 0 for interface in self.iw_runner.list_interfaces(): if self.inherit_interfaces: self._interfaces.append( NetDev(inherited=True, if_name=interface.if_name, if_type=interface.if_type, phy=interface.phy)) else: self.iw_runner.remove_interface(interface.if_name) self._wlanifs_in_use = [] self._local_macs_in_use = set() self._capture_interface = None self._board = None # Some uses of LinuxSystem don't use the interface allocation facility. # Don't force us to remove all the existing interfaces if this facility # is not desired. self._wlanifs_initialized = False self._capabilities = None self._ping_runner = ping_runner.PingRunner(host=self.host) self._bridge_interface = None self._virtual_ethernet_pair = None
def assert_scanning_fails(cls, client, scan_freq): """Initiates a single-channel scan, and verifies that it fails. @param client The WiFiClient object for the DUT. @param scan_freq The frequency (in MHz) on which to scan. """ client.claim_wifi_if() # Stop shill/supplicant scans. try: # We use IwRunner directly here, because WiFiClient.scan() # wants a scan to succeed, while we want the scan to fail. if iw_runner.IwRunner(client.host).timed_scan( client.wifi_if, [scan_freq], [cls.MISSING_SSID]): # We should have got None, to represent failure. raise error.TestFail( 'Scan succeeded (and was expected to fail).') finally: client.release_wifi_if()
def run_once(self): """Configures a DUT to behave as if it was manufactured for a particular region. Then verifies that the DUT connects, or fails to connect, per expectations. """ num_failures = 0 try: self.fake_up_region(self.region_name) self.assert_equal( 'country code', iw_runner.IwRunner(self.host).get_regulatory_domain(), self.expected_country_code) num_mismatches = self.count_mismatched_phy_configs( self.host, self.channel_infos) if num_mismatches: raise error.TestFail( '%d phy configs were not as expected (see below)' % num_mismatches) wifi_context = wifi_test_context_manager.WiFiTestContextManager( self.__class__.__name__, self.host, self.cmdline_args, self.debugdir) with wifi_context: wifi_context.router.reboot(timeout=self.REBOOT_TIMEOUT_SECS) for channel_config in self.channel_infos: try: self.test_channel(wifi_context, channel_config) except error.TestFail as e: # Log the error, but keep going. This way, we # get a full report of channels where behavior # differs from expectations. logging.error('Verification failed for |%s|: %s', self.region_name, channel_config) logging.error(e) num_failures += 1 finally: if num_failures: raise error.TestFail( 'Verification failed for %d channel configs (see below)' % num_failures) self.host.run(self.VPD_CLEAN_COMMAND) self.host.reboot(timeout=self.REBOOT_TIMEOUT_SECS, wait=True)
def run(self, job, batch_size=7, tries=10, capturer_hostname=None, conn_worker=None, work_client_hostname=None, disabled_sysinfo=False): """Executes Chaos test. @param job: an Autotest job object. @param batch_size: an integer, max number of APs to lock in one batch. @param tries: an integer, number of iterations to run per AP. @param capturer_hostname: a string or None, hostname or IP of capturer. @param conn_worker: ConnectionWorkerAbstract or None, to run extra work after successful connection. @param work_client_hostname: a string or None, hostname of work client @param disabled_sysinfo: a bool, disable collection of logs from DUT. @raises TestError: Issues locking VM webdriver instance """ lock_manager = host_lock_manager.HostLockManager() webdriver_master = hosts.SSHHost(MASTERNAME, user='******') with host_lock_manager.HostsLockedBy(lock_manager): capture_host = utils.allocate_packet_capturer( lock_manager, hostname=capturer_hostname) # Cleanup and reboot packet capturer before the test. utils.sanitize_client(capture_host) capturer = site_linux_system.LinuxSystem(capture_host, {}, 'packet_capturer') # Run iw scan and abort if more than allowed number of APs are up. iw_command = iw_runner.IwRunner(capture_host) start_time = time.time() logging.info('Performing a scan with a max timeout of 30 seconds.') while time.time() - start_time <= ap_constants.MAX_SCAN_TIMEOUT: networks = iw_command.scan('wlan0') if networks is None: if (time.time() - start_time == ap_constants.MAX_SCAN_TIMEOUT): raise error.TestError( 'Packet capturer is not responding to scans. Check' 'device and re-run test') continue elif len(networks) < ap_constants.MAX_SSID_COUNT: break elif len(networks) >= ap_constants.MAX_SSID_COUNT: raise error.TestError( 'Probably someone is already running a' 'chaos test?!') if conn_worker is not None: work_client_machine = utils.allocate_packet_capturer( lock_manager, hostname=work_client_hostname) conn_worker.prepare_work_client(work_client_machine) webdriver_instance = utils.allocate_webdriver_instance( lock_manager) self._ap_spec._webdriver_hostname = webdriver_instance # If a test is cancelled or aborted the VM may be left on. Always # turn of the VM to return it to a clean state. try: logging.info('Always power off VM %s', webdriver_instance) utils.power_off_VM(webdriver_master, webdriver_instance) except: logging.debug('VM was already off, ignoring.') logging.info('Starting up VM %s', webdriver_instance) utils.power_on_VM(webdriver_master, webdriver_instance) batch_locker = ap_batch_locker.ApBatchLocker( lock_manager, self._ap_spec, ap_test_type=ap_constants.AP_TEST_TYPE_CHAOS) while batch_locker.has_more_aps(): # Work around crbug.com/358716 utils.sanitize_client(self._host) healthy_dut = True with contextlib.closing( wifi_client.WiFiClient( hosts.create_host(self._host.hostname), './debug', False)) as client: aps = batch_locker.get_ap_batch(batch_size=batch_size) if not aps: logging.info('No more APs to test.') break # Power down all of the APs because some can get grumpy # if they are configured several times and remain on. # User the cartridge to down group power downs and # configurations. utils.power_down_aps(aps, self._broken_pdus) utils.configure_aps(aps, self._ap_spec, self._broken_pdus) aps = utils.filter_quarantined_and_config_failed_aps( aps, batch_locker, job, self._broken_pdus) for ap in aps: # http://crbug.com/306687 if ap.ssid == None: logging.error('The SSID was not set for the AP:%s', ap) healthy_dut = utils.is_dut_healthy(client, ap) if not healthy_dut: logging.error('DUT is not healthy, rebooting.') batch_locker.unlock_and_reclaim_aps() break networks = utils.return_available_networks( ap, capturer, job, self._ap_spec) if networks is None: # If scan returned no networks, iw scan failed. # Reboot the packet capturer device and # reconfigure the capturer. batch_locker.unlock_and_reclaim_ap(ap.host_name) logging.error('Packet capture is not healthy, ' 'rebooting.') capturer.host.reboot() capturer = site_linux_system.LinuxSystem( capture_host, {}, 'packet_capturer') continue if networks == list(): # Packet capturer did not find the SSID in scan or # there was a security mismatch. utils.release_ap(ap, batch_locker, self._broken_pdus) continue assoc_params = ap.get_association_parameters() if not utils.is_conn_worker_healthy( conn_worker, ap, assoc_params, job): utils.release_ap(ap, batch_locker, self._broken_pdus) continue name = ap.name kernel_ver = self._host.get_kernel_ver() firmware_ver = utils.get_firmware_ver(self._host) if not firmware_ver: firmware_ver = "Unknown" debug_dict = { '+++PARSE DATA+++': '+++PARSE DATA+++', 'SSID': ap._ssid, 'DUT': client.wifi_mac, 'AP Info': ap.name, 'kernel_version': kernel_ver, 'wifi_firmware_version': firmware_ver } debug_string = pprint.pformat(debug_dict) logging.info( 'Waiting %d seconds for the AP dhcp ' 'server', ap.dhcp_delay) time.sleep(ap.dhcp_delay) result = job.run_test( self._test, capturer=capturer, capturer_frequency=networks[0].frequency, capturer_ht_type=networks[0].ht, host=self._host, assoc_params=assoc_params, client=client, tries=tries, debug_info=debug_string, # Copy all logs from the system disabled_sysinfo=disabled_sysinfo, conn_worker=conn_worker, tag=ap.ssid if conn_worker is None else '%s.%s' % (conn_worker.name, ap.ssid)) utils.release_ap(ap, batch_locker, self._broken_pdus) if conn_worker is not None: conn_worker.cleanup() if not healthy_dut: continue batch_locker.unlock_aps() capturer.close() logging.info('Powering off VM %s', webdriver_instance) utils.power_off_VM(webdriver_master, webdriver_instance) lock_manager.unlock(webdriver_instance) if self._broken_pdus: logging.info('PDU is down!!!\nThe following PDUs are down:\n') pprint.pprint(self._broken_pdus)
def test_station_dump(self): """Test parsing of a station dump.""" host = self.host(self.STATION_DUMP_INFORMATION) runner = iw_runner.IwRunner(remote_host=host) self.assertEquals(runner.get_station_dump(self.STATION_DUMP_IFACE), self.STATION_DUMP_INFORMATION_PARSED)
def test_vht_supported(self): """Test VHT support parsing.""" host = self.host(self.VHT_IW_INFO) runner = iw_runner.IwRunner(remote_host=host) self.assertEquals(runner.vht_supported(), True)
def run_once(self): """Body of the test.""" get_assoc_params = lambda conf: xmlrpc_datatypes.AssociationParameters( ssid=self.context.router.get_ssid(instance=0), bgscan_config=conf) get_ping_config = lambda period: ping_runner.PingConfig( self.context.get_wifi_addr(), interval=self.PING_INTERVAL_SECONDS, count=int(period / self.PING_INTERVAL_SECONDS)) self.context.configure(hostap_config.HostapConfig(channel=1)) bgscan_config = xmlrpc_datatypes.BgscanConfiguration( short_interval=self.CONFIGURED_BGSCAN_INTERVAL_SECONDS, long_interval=self.CONFIGURED_BGSCAN_INTERVAL_SECONDS, method=xmlrpc_datatypes.BgscanConfiguration.SCAN_METHOD_SIMPLE) self.context.assert_connect_wifi(get_assoc_params(bgscan_config)) logging.info('Pinging router with background scans for %d seconds.', self.BGSCAN_SAMPLE_PERIOD_SECONDS) result_bgscan = self.context.client.ping( get_ping_config(self.BGSCAN_SAMPLE_PERIOD_SECONDS)) logging.info('Ping statistics with bgscan: %r', result_bgscan) # Bring up a second AP, make sure that it shows up in bgscans. self.context.configure(hostap_config.HostapConfig( channel=11, min_streams=1, ssid=self.context.router.get_ssid()), multi_interface=True) logging.info('Without a ping running, ensure that bgscans succeed.') ap_mac = self.context.router.get_hostapd_mac(ap_num=1) logging.debug('Looking for BSS %s', ap_mac) iw = iw_runner.IwRunner(remote_host=self.context.client.host) start_time = time.time() while time.time() - start_time < self.BGSCAN_SAMPLE_PERIOD_SECONDS: bsses = iw.scan_dump(self.context.client.wifi_if) logging.debug('Found BSSes: %r', bsses) if filter(lambda bss: bss.bss == ap_mac, bsses): break time.sleep(1) else: raise error.TestFail('Background scans should detect new BSSes ' 'within an associated ESS.') self.context.router.deconfig_aps(instance=1) self.context.client.shill.disconnect( self.context.router.get_ssid(instance=0)) # Reconfigure AP, so the new bgscan setting can be correctly applied. self.context.configure(hostap_config.HostapConfig(channel=1)) # Gather some statistics about ping latencies without scanning going on. self.context.assert_connect_wifi(get_assoc_params(None)) logging.info('Pinging router without background scans for %d seconds.', self.NO_BGSCAN_SAMPLE_PERIOD_SECONDS) result_no_bgscan = self.context.client.ping( get_ping_config(self.NO_BGSCAN_SAMPLE_PERIOD_SECONDS)) logging.info('Ping statistics without bgscan: %r', result_no_bgscan) if result_no_bgscan.max_latency > self.THRESHOLD_BASELINE_LATENCY_MS: raise error.TestFail('RTT latency is too high even without ' 'background scans: %f' % result_no_bgscan.max_latency) # Dwell time for scanning is usually configured to be around 100 ms, # since this is also the standard beacon interval. Tolerate spikes in # latency up to 200 ms as a way of asking that our PHY be servicing # foreground traffic regularly during background scans. if (result_bgscan.max_latency > self.LATENCY_MARGIN_MS + result_no_bgscan.avg_latency): raise error.TestFail( 'Significant difference in rtt due to bgscan: ' '%.1f > %.1f + %d' % (result_bgscan.max_latency, result_no_bgscan.avg_latency, self.LATENCY_MARGIN_MS))
def run(self, job, batch_size=10, tries=10, capturer_hostname=None, conn_worker=None, work_client_hostname=None, disabled_sysinfo=False): """Executes Chaos test. @param job: an Autotest job object. @param batch_size: an integer, max number of APs to lock in one batch. @param tries: an integer, number of iterations to run per AP. @param capturer_hostname: a string or None, hostname or IP of capturer. @param conn_worker: ConnectionWorkerAbstract or None, to run extra work after successful connection. @param work_client_hostname: a string or None, hostname of work client @param disabled_sysinfo: a bool, disable collection of logs from DUT. @raises TestError: Packet capture DUT may be down or another test may be running in the chamber. """ lock_manager = host_lock_manager.HostLockManager() host_prefix = self._host.hostname.split('-')[0] if ap_constants.CASEY5 in host_prefix: test_type = ap_constants.AP_TEST_TYPE_CASEY5 elif ap_constants.CASEY7 in host_prefix: test_type = ap_constants.AP_TEST_TYPE_CASEY7 else: test_type = None with host_lock_manager.HostsLockedBy(lock_manager): capture_host = utils.allocate_packet_capturer( lock_manager, hostname=capturer_hostname, prefix=host_prefix) # Cleanup and reboot packet capturer before the test. utils.sanitize_client(capture_host) capturer = site_linux_system.LinuxSystem(capture_host, {}, 'packet_capturer') # Run iw scan and abort if more than allowed number of APs are up. iw_command = iw_runner.IwRunner(capture_host) start_time = time.time() logging.info('Performing a scan with a max timeout of 30 seconds.') capture_interface = 'wlan0' capturer_info = capture_host.run('cat /etc/lsb-release', ignore_status=True, timeout=5).stdout if 'whirlwind' in capturer_info: # Use the dual band aux radio for scanning networks. capture_interface = 'wlan2' while time.time() - start_time <= ap_constants.MAX_SCAN_TIMEOUT: networks = iw_command.scan(capture_interface) if networks is None: if (time.time() - start_time == ap_constants.MAX_SCAN_TIMEOUT): raise error.TestError( 'Packet capturer is not responding to scans. Check' 'device and re-run test') continue elif len(networks) < ap_constants.MAX_SSID_COUNT: break elif len(networks) >= ap_constants.MAX_SSID_COUNT: raise error.TestError( 'Probably someone is already running a ' 'chaos test?!') if conn_worker is not None: work_client_machine = utils.allocate_packet_capturer( lock_manager, hostname=work_client_hostname) conn_worker.prepare_work_client(work_client_machine) batch_locker = ap_batch_locker.ApBatchLocker( lock_manager, self._ap_spec, ap_test_type=test_type) while batch_locker.has_more_aps(): # Work around for CrOS devices only:crbug.com/358716 # Do not reboot Android devices:b/27977927 if self._host.get_os_type() != adb_host.OS_TYPE_ANDROID: utils.sanitize_client(self._host) healthy_dut = True with contextlib.closing( wifi_client.WiFiClient( hosts.create_host( { 'hostname': self._host.hostname, 'afe_host': self._host._afe_host }, host_class=self._host.__class__), './debug', False)) as client: aps = batch_locker.get_ap_batch(batch_size=batch_size) if not aps: logging.info('No more APs to test.') break utils.configure_aps(aps, self._ap_spec) aps = utils.filter_quarantined_and_config_failed_aps( aps, batch_locker, job) for ap in aps: # http://crbug.com/306687 if ap.ssid == None: logging.error('The SSID was not set for the AP:%s', ap) healthy_dut = utils.is_dut_healthy(client, ap) if not healthy_dut: logging.error('DUT is not healthy, rebooting.') batch_locker.unlock_and_reclaim_aps() break networks = utils.return_available_networks( ap, capturer, job, self._ap_spec) if networks is None: # If scan returned no networks, iw scan failed. # Reboot the packet capturer device and # reconfigure the capturer. batch_locker.unlock_and_reclaim_ap(ap.host_name) logging.error('Packet capture is not healthy, ' 'rebooting.') capturer.host.reboot() capturer = site_linux_system.LinuxSystem( capture_host, {}, 'packet_capturer') continue if networks == list(): # Packet capturer did not find the SSID in scan or # there was a security mismatch. utils.release_ap(ap, batch_locker) continue assoc_params = ap.get_association_parameters() if not utils.is_conn_worker_healthy( conn_worker, ap, assoc_params, job): utils.release_ap(ap, batch_locker) continue name = ap.name kernel_ver = self._host.get_kernel_ver() firmware_ver = utils.get_firmware_ver(self._host) if not firmware_ver: firmware_ver = "Unknown" debug_dict = { '+++PARSE DATA+++': '+++PARSE DATA+++', 'SSID': ap._ssid, 'DUT': client.wifi_mac, 'AP Info': ap.name, 'kernel_version': kernel_ver, 'wifi_firmware_version': firmware_ver } debug_string = pprint.pformat(debug_dict) logging.info( 'Waiting %d seconds for the AP dhcp ' 'server', ap.dhcp_delay) time.sleep(ap.dhcp_delay) result = job.run_test( self._test, capturer=capturer, capturer_frequency=networks[0].frequency, capturer_ht_type=networks[0].ht, host=self._host, assoc_params=assoc_params, client=client, tries=tries, debug_info=debug_string, # Copy all logs from the system disabled_sysinfo=disabled_sysinfo, conn_worker=conn_worker, tag=ap.ssid if conn_worker is None else '%s.%s' % (conn_worker.name, ap.ssid)) utils.release_ap(ap, batch_locker) if conn_worker is not None: conn_worker.cleanup() if not healthy_dut: continue batch_locker.unlock_aps() capturer.close() factory = ap_configurator_factory.APConfiguratorFactory(test_type) factory.turn_off_all_routers([])
def test_he_supported(self): """Test HE support parsing.""" host = self.host(self.HE_IW_INFO) runner = iw_runner.IwRunner(remote_host=host) self.assertEquals(runner.he_supported(), True)
def run(self, job, batch_size=10, tries=10, capturer_hostname=None, conn_worker=None, work_client_hostname=None, disabled_sysinfo=False): """Executes Chaos test. @param job: an Autotest job object. @param batch_size: an integer, max number of APs to lock in one batch. @param tries: an integer, number of iterations to run per AP. @param capturer_hostname: a string or None, hostname or IP of capturer. @param conn_worker: ConnectionWorkerAbstract or None, to run extra work after successful connection. @param work_client_hostname: a string or None, hostname of work client @param disabled_sysinfo: a bool, disable collection of logs from DUT. @raises TestError: Issues locking VM webdriver instance """ lock_manager = host_lock_manager.HostLockManager() webdriver_master = hosts.SSHHost(MASTERNAME, user='******') host_prefix = self._host.hostname.split('-')[0] with host_lock_manager.HostsLockedBy(lock_manager): capture_host = utils.allocate_packet_capturer( lock_manager, hostname=capturer_hostname, prefix=host_prefix) # Cleanup and reboot packet capturer before the test. utils.sanitize_client(capture_host) capturer = site_linux_system.LinuxSystem(capture_host, {}, 'packet_capturer') # Run iw scan and abort if more than allowed number of APs are up. iw_command = iw_runner.IwRunner(capture_host) start_time = time.time() logging.info('Performing a scan with a max timeout of 30 seconds.') capture_interface = 'wlan0' capturer_info = capture_host.run('cat /etc/lsb-release', ignore_status=True, timeout=5).stdout if 'whirlwind' in capturer_info: # Use the dual band aux radio for scanning networks. capture_interface = 'wlan2' while time.time() - start_time <= ap_constants.MAX_SCAN_TIMEOUT: networks = iw_command.scan(capture_interface) if networks is None: if (time.time() - start_time == ap_constants.MAX_SCAN_TIMEOUT): raise error.TestError( 'Packet capturer is not responding to scans. Check' 'device and re-run test') continue elif len(networks) < ap_constants.MAX_SSID_COUNT: break elif len(networks) >= ap_constants.MAX_SSID_COUNT: raise error.TestError( 'Probably someone is already running a ' 'chaos test?!') if conn_worker is not None: work_client_machine = utils.allocate_packet_capturer( lock_manager, hostname=work_client_hostname) conn_worker.prepare_work_client(work_client_machine) # Lock VM. If on, power off; always power on. Then create a tunnel. webdriver_instance = utils.allocate_webdriver_instance(lock_manager) if utils.is_VM_running(webdriver_master, webdriver_instance): logging.info('VM %s was on; powering off for a clean instance', webdriver_instance) utils.power_off_VM(webdriver_master, webdriver_instance) logging.info('Allow VM time to gracefully shut down') time.sleep(5) logging.info('Starting up VM %s', webdriver_instance) utils.power_on_VM(webdriver_master, webdriver_instance) logging.info('Allow VM time to power on before creating a tunnel.') time.sleep(30) if not client_utils.host_is_in_lab_zone(webdriver_instance.hostname): self._ap_spec._webdriver_hostname = webdriver_instance.hostname else: # If in the lab then port forwarding must be done so webdriver # connection will be over localhost. self._ap_spec._webdriver_hostname = 'localhost' webdriver_tunnel = webdriver_instance.create_ssh_tunnel( WEBDRIVER_PORT, WEBDRIVER_PORT) logging.info('Wait for tunnel to be created.') for i in range(3): time.sleep(10) results = client_utils.run('lsof -i:%s' % WEBDRIVER_PORT, ignore_status=True) if results: break if not results: raise error.TestError( 'Unable to listen to WEBDRIVER_PORT: %s', results) batch_locker = ap_batch_locker.ApBatchLocker( lock_manager, self._ap_spec, ap_test_type=ap_constants.AP_TEST_TYPE_CHAOS) while batch_locker.has_more_aps(): # Work around for CrOS devices only:crbug.com/358716 utils.sanitize_client(self._host) healthy_dut = True with contextlib.closing(wifi_client.WiFiClient( hosts.create_host( { 'hostname' : self._host.hostname, 'afe_host' : self._host._afe_host, 'host_info_store': self._host.host_info_store, }, host_class=self._host.__class__, ), './debug', False, )) as client: aps = batch_locker.get_ap_batch(batch_size=batch_size) if not aps: logging.info('No more APs to test.') break # Power down all of the APs because some can get grumpy # if they are configured several times and remain on. # User the cartridge to down group power downs and # configurations. utils.power_down_aps(aps, self._broken_pdus) utils.configure_aps(aps, self._ap_spec, self._broken_pdus) aps = utils.filter_quarantined_and_config_failed_aps(aps, batch_locker, job, self._broken_pdus) for ap in aps: # http://crbug.com/306687 if ap.ssid == None: logging.error('The SSID was not set for the AP:%s', ap) healthy_dut = utils.is_dut_healthy(client, ap) if not healthy_dut: logging.error('DUT is not healthy, rebooting.') batch_locker.unlock_and_reclaim_aps() break networks = utils.return_available_networks( ap, capturer, job, self._ap_spec) if networks is None: # If scan returned no networks, iw scan failed. # Reboot the packet capturer device and # reconfigure the capturer. batch_locker.unlock_and_reclaim_ap(ap.host_name) logging.error('Packet capture is not healthy, ' 'rebooting.') capturer.host.reboot() capturer = site_linux_system.LinuxSystem( capture_host, {},'packet_capturer') continue if networks == list(): # Packet capturer did not find the SSID in scan or # there was a security mismatch. utils.release_ap(ap, batch_locker, self._broken_pdus) continue assoc_params = ap.get_association_parameters() if not utils.is_conn_worker_healthy( conn_worker, ap, assoc_params, job): utils.release_ap( ap, batch_locker, self._broken_pdus) continue name = ap.name kernel_ver = self._host.get_kernel_ver() firmware_ver = utils.get_firmware_ver(self._host) if not firmware_ver: firmware_ver = "Unknown" debug_dict = {'+++PARSE DATA+++': '+++PARSE DATA+++', 'SSID': ap._ssid, 'DUT': client.wifi_mac, 'AP Info': ap.name, 'kernel_version': kernel_ver, 'wifi_firmware_version': firmware_ver} debug_string = pprint.pformat(debug_dict) logging.info('Waiting %d seconds for the AP dhcp ' 'server', ap.dhcp_delay) time.sleep(ap.dhcp_delay) result = job.run_test(self._test, capturer=capturer, capturer_frequency=networks[0].frequency, capturer_ht_type=networks[0].ht, host=self._host, assoc_params=assoc_params, client=client, tries=tries, debug_info=debug_string, # Copy all logs from the system disabled_sysinfo=disabled_sysinfo, conn_worker=conn_worker, tag=ap.ssid if conn_worker is None else '%s.%s' % (conn_worker.name, ap.ssid)) utils.release_ap(ap, batch_locker, self._broken_pdus) if conn_worker is not None: conn_worker.cleanup() if not healthy_dut: continue batch_locker.unlock_aps() if webdriver_tunnel: webdriver_instance.disconnect_ssh_tunnel(webdriver_tunnel, WEBDRIVER_PORT) webdriver_instance.close() capturer.close() logging.info('Powering off VM %s', webdriver_instance) utils.power_off_VM(webdriver_master, webdriver_instance) lock_manager.unlock(webdriver_instance.hostname) if self._broken_pdus: logging.info('PDU is down!!!\nThe following PDUs are down:\n') pprint.pprint(self._broken_pdus) factory = ap_configurator_factory.APConfiguratorFactory( ap_constants.AP_TEST_TYPE_CHAOS) factory.turn_off_all_routers(self._broken_pdus)
def run_once(self, host=None, ssid=None, passphrase=None, wifi_iface=None, wifi_ssid=None): """Check that a given wifi interface is properly configured. @param host: a host object representing the DUT. @param ssid: A string representing the ssid to connect to. @param passphrase: A string representing the passphrase to the ssid. @param wifi_iface: Name of the wifi interface to test; None means we'll try to detect at least one that works. @param wifi_ssid: Name of the SSID we want the interface to be connected to; None means any. @raise TestFail: The test failed. """ self.host = host if afe_utils.host_in_lab(host): ssid = site_utils.get_wireless_ssid(host.hostname) passphrase = global_config.global_config.get_config_value( 'CLIENT', 'wireless_password', default=None) with host_utils.connect_to_ssid(host, ssid, passphrase): err_iface = ('No interface is' if wifi_iface is None else 'Interface %s is not' % wifi_iface) # First check link status and SSID. iw = iw_runner.IwRunner(remote_host=host) active_ifaces = [] try: iw_ifaces = [ iface_tuple.if_name for iface_tuple in iw.list_interfaces() ] if wifi_iface is not None: if wifi_iface not in iw_ifaces: raise error.TestFail('Interface %s not listed by iw' % wifi_iface) test_ifaces = [wifi_iface] else: test_ifaces = iw_ifaces for iface in test_ifaces: iface_ssid = iw.get_link_value(iface, 'SSID') if (iface_ssid is not None and (wifi_ssid is None or iface_ssid == wifi_ssid)): active_ifaces.append(iface) except error.GenericHostRunError: raise error.TestFail('Failed to run iw') if not active_ifaces: err_ssid = 'any SSID' if wifi_ssid is None else ('SSID ' + wifi_ssid) raise error.TestFail('%s connected to %s' % (err_iface, err_ssid)) logging.info('Active wifi interfaces: %s', ', '.join(active_ifaces)) # Then check IPv4 connectivity. try: ifconfig_output = host.run_output('ifconfig').splitlines() except error.GenericHostRunError: raise error.TestFail('Failed to run ifconfig') ifconfig_dict = self.get_ifconfig_dict(ifconfig_output) connected_ifaces = [ iface for iface in active_ifaces if any([ 'inet addr:' in line for line in ifconfig_dict.get(iface, []) ]) ] if not connected_ifaces: raise error.TestFail('%s IPv4 connected' % err_iface) logging.info('IPv4 connected wifi interfaces: %s', ', '.join(connected_ifaces))
def test_radio_information(self): """Test radio information parsing.""" host = self.host(self.INFO_AP_MODE) runner = iw_runner.IwRunner(remote_host=host) self.assertEquals(runner.get_radio_config(self.INFO_IFACE), self.RADIO_CONFIG_AP_MODE)
def test_fragmentation_threshold(self): """Test fragmentation threshold parsing.""" host = self.host(self.PHY_INFO_FRAGMENTATION) runner = iw_runner.IwRunner(remote_host=host) self.assertEquals(runner.get_fragmentation_threshold(self.INFO_PHY), self.PHY_FRAGMENTATION_THRESHOLD)
def test_operating_mode_station(self): """Test STA operating mode parsing.""" host = self.host(self.INFO_STA_MODE) runner = iw_runner.IwRunner(remote_host=host) self.assertEquals(runner.get_operating_mode(self.INFO_IFACE), iw_runner.DEV_MODE_STATION)
def test_operating_mode_ap(self): """Test AP operating mode parsing.""" host = self.host(self.INFO_AP_MODE) runner = iw_runner.IwRunner(remote_host=host) self.assertEquals(runner.get_operating_mode(self.INFO_IFACE), iw_runner.DEV_MODE_AP)
def test_operating_mode_mesh(self): """Test mesh operating mode parsing.""" host = self.host(self.INFO_MESH_MODE) runner = iw_runner.IwRunner(remote_host=host) self.assertEquals(runner.get_operating_mode(self.INFO_IFACE), iw_runner.DEV_MODE_MESH_POINT)
def run_once(self, host): helper = privet_helper.PrivetHelper(host=host) logging.info('Looking for privet bootstrapping network from DUT.') scan_interface = self._router.get_wlanif(2437, 'managed') self._router.host.run('%s link set %s up' % (self._router.cmd_ip, scan_interface)) start_time = time.time() privet_bss = None while time.time() - start_time < PRIVET_AP_STARTUP_TIMEOUT_SECONDS: bss_list = self._router.iw_runner.scan(scan_interface) for bss in bss_list or []: if helper.is_softap_ssid(bss.ssid): privet_bss = bss if privet_bss is None: raise error.TestFail('Device did not start soft AP in time.') self._router.release_interface(scan_interface) # Get the netblock of the interface running the AP. dut_iw_runner = iw_runner.IwRunner(remote_host=host) devs = dut_iw_runner.list_interfaces(desired_if_type='AP') if not devs: raise error.TestFail('No AP devices on DUT?') ap_interface = interface.Interface(devs[0].if_name, host=host) ap_netblock = netblock.from_addr(ap_interface.ipv4_address_and_prefix) # Set up an AP on the router in the 5Ghz range with WPA2 security. wpa_config = xmlrpc_security_types.WPAConfig( psk=PASSPHRASE, wpa_mode=xmlrpc_security_types.WPAConfig.MODE_PURE_WPA2, wpa2_ciphers=[xmlrpc_security_types.WPAConfig.CIPHER_CCMP]) router_conf = hostap_config.HostapConfig( frequency=5240, security_config=wpa_config, mode=hostap_config.HostapConfig.MODE_11N_PURE) self._router.hostap_configure(router_conf) # Connect the other interface on the router to the AP on the client # at a hardcoded IP address. self._router.configure_managed_station( privet_bss.ssid, privet_bss.frequency, ap_netblock.get_addr_in_block(200)) station_interface = self._router.get_station_interface(instance=0) logging.debug('Set up station on %s', station_interface) self._router.ping(ping_runner.PingConfig(ap_netblock.addr, count=3)) logging.info('Looking for privet webserver in mDNS records.') start_time = time.time() while time.time() - start_time < PRIVET_MDNS_RECORD_TIMEOUT_SECONDS: all_records = avahi_utils.avahi_browse(host=self._router.host) records = [record for record in all_records if (record.interface == station_interface and record.record_type == '_privet._tcp')] if records: break time.sleep(POLLING_PERIOD) if not records: raise error.TestFail('Did not find privet mDNS records in time.') if len(records) > 1: raise error.TestFail('Should not see multiple privet records.') privet_record = records[0] # TODO(wiley) pull the HTTPs port number out of the /info API. helper = privet_helper.PrivetdHelper( host=self._router.host, hostname=privet_record.address, http_port=int(privet_record.port)) helper.ping_server() # Now configure the client with WiFi credentials. auth_token = helper.privet_auth() ssid = self._router.get_ssid() data = helper.setup_add_wifi_credentials(ssid, PASSPHRASE) helper.setup_start(data, auth_token) logging.info('Waiting for DUT to connect to router network.') start_time = time.time() # Wait for the DUT to take down the AP. while time.time() - start_time < PRIVET_CONNECT_TIMEOUT_SECONDS: if not dut_iw_runner.list_interfaces(desired_if_type='AP'): break time.sleep(POLLING_PERIOD) else: raise error.TestFail('Timeout waiting for DUT to take down AP.') # But we should be able to ping the client from the router's AP. while time.time() - start_time < PRIVET_CONNECT_TIMEOUT_SECONDS: if dut_iw_runner.list_interfaces(desired_if_type='managed'): break time.sleep(POLLING_PERIOD) else: raise error.TestFail('Timeout waiting for DUT managerd interface.') while time.time() - start_time < PRIVET_CONNECT_TIMEOUT_SECONDS: devs = dut_iw_runner.list_interfaces(desired_if_type='managed') if devs: managed_interface = interface.Interface(devs[0].if_name, host=host) # Check if we have an IP yet. if managed_interface.ipv4_address_and_prefix: break time.sleep(POLLING_PERIOD) else: raise error.TestFail('Timeout waiting for DUT managerd interface.') managed_netblock = netblock.from_addr( managed_interface.ipv4_address_and_prefix) while time.time() - start_time < PRIVET_CONNECT_TIMEOUT_SECONDS: PING_COUNT = 3 result = self._router.ping( ping_runner.PingConfig(managed_netblock.addr, ignore_result=True, count=PING_COUNT)) if result.received == PING_COUNT: break time.sleep(POLLING_PERIOD) else: raise error.TestFail('Timeout before ping was successful.') # And buffet should think it is online as well. helper = privet_helper.PrivetdHelper( host=host, hostname=managed_netblock.addr, http_port=int(privet_record.port)) helper.ping_server() if not helper.wifi_setup_was_successful(ssid, auth_token): raise error.TestFail('Device claims to be offline, but is online.')
def test_station_bssid(self): """Test parsing of the bssid of a station-mode link.""" host = self.host(self.STATION_LINK_INFORMATION) runner = iw_runner.IwRunner(remote_host=host) self.assertEquals(runner.get_current_bssid(self.STATION_LINK_IFACE), self.STATION_LINK_BSSID)