1# Copyright 2016 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 5import contextlib 6import datetime 7import logging 8import pprint 9import time 10 11import common 12from autotest_lib.client.common_lib import error 13from autotest_lib.client.common_lib.cros.network import ap_constants 14from autotest_lib.client.common_lib.cros.network import iw_runner 15from autotest_lib.server import hosts 16from autotest_lib.server import site_linux_system 17from autotest_lib.server.cros import host_lock_manager 18from autotest_lib.server.cros.ap_configurators import ap_batch_locker 19from autotest_lib.server.cros.ap_configurators \ 20 import ap_configurator_factory 21from autotest_lib.server.cros.network import chaos_clique_utils as utils 22from autotest_lib.server.cros.network import wifi_client 23 24 25class StaticRunner(object): 26 """Object to run a network_WiFi_ChaosXXX test.""" 27 28 29 def __init__(self, test, host, spec): 30 """Initializes and runs test. 31 32 @param test: a string, test name. 33 @param host: an Autotest host object, device under test. 34 @param spec: an APSpec object. 35 36 """ 37 self._test = test 38 self._host = host 39 self._ap_spec = spec 40 # Log server and DUT times 41 dt = datetime.datetime.now() 42 logging.info('Server time: %s', dt.strftime('%a %b %d %H:%M:%S %Y')) 43 logging.info('DUT time: %s', self._host.run('date').stdout.strip()) 44 45 46 def run(self, job, batch_size=10, tries=2, capturer_hostname=None, 47 conn_worker=None, work_client_hostname=None, 48 disabled_sysinfo=False): 49 """Executes Chaos test. 50 51 @param job: an Autotest job object. 52 @param batch_size: an integer, max number of APs to lock in one batch. 53 @param tries: an integer, number of iterations to run per AP. 54 @param capturer_hostname: a string or None, hostname or IP of capturer. 55 @param conn_worker: ConnectionWorkerAbstract or None, to run extra 56 work after successful connection. 57 @param work_client_hostname: a string or None, hostname of work client 58 @param disabled_sysinfo: a bool, disable collection of logs from DUT. 59 60 61 @raises TestError: Packet capture DUT may be down or another test may be 62 running in the chamber. 63 """ 64 65 lock_manager = host_lock_manager.HostLockManager() 66 host_prefix = self._host.hostname.split('-')[0] 67 68 with host_lock_manager.HostsLockedBy(lock_manager): 69 capture_host = utils.allocate_packet_capturer( 70 lock_manager, hostname=capturer_hostname, 71 prefix=host_prefix) 72 # Cleanup and reboot packet capturer before the test. 73 utils.sanitize_client(capture_host) 74 capturer = site_linux_system.LinuxSystem(capture_host, {}, 75 'packet_capturer') 76 77 # Run iw scan and abort if more than allowed number of APs are up. 78 iw_command = iw_runner.IwRunner(capture_host) 79 start_time = time.time() 80 logging.info('Performing a scan with a max timeout of 30 seconds.') 81 capture_interface = 'wlan0' 82 capturer_info = capture_host.run('cat /etc/lsb-release', 83 ignore_status=True, timeout=5).stdout 84 if 'whirlwind' in capturer_info: 85 # Use the dual band aux radio for scanning networks. 86 capture_interface = 'wlan2' 87 while time.time() - start_time <= ap_constants.MAX_SCAN_TIMEOUT: 88 networks = iw_command.scan(capture_interface) 89 if networks is None: 90 if (time.time() - start_time == 91 ap_constants.MAX_SCAN_TIMEOUT): 92 raise error.TestError( 93 'Packet capturer is not responding to scans. Check' 94 'device and re-run test') 95 continue 96 elif len(networks) < ap_constants.MAX_SSID_COUNT: 97 break 98 elif len(networks) >= ap_constants.MAX_SSID_COUNT: 99 raise error.TestError( 100 'Probably someone is already running a ' 101 'chaos test?!') 102 103 if conn_worker is not None: 104 work_client_machine = utils.allocate_packet_capturer( 105 lock_manager, hostname=work_client_hostname) 106 conn_worker.prepare_work_client(work_client_machine) 107 108 batch_locker = ap_batch_locker.ApBatchLocker( 109 lock_manager, self._ap_spec, 110 ap_test_type=ap_constants.AP_TEST_TYPE_CHAOS) 111 112 while batch_locker.has_more_aps(): 113 # Work around for CrOS devices only:crbug.com/358716 114 utils.sanitize_client(self._host) 115 healthy_dut = True 116 117 with contextlib.closing(wifi_client.WiFiClient( 118 hosts.create_host( 119 { 120 'hostname' : self._host.hostname, 121 'afe_host' : self._host._afe_host, 122 'host_info_store' : 123 self._host.host_info_store, 124 }, 125 host_class=self._host.__class__, 126 ), 127 './debug', 128 False, 129 )) as client: 130 131 aps = batch_locker.get_ap_batch(batch_size=batch_size) 132 if not aps: 133 logging.info('No more APs to test.') 134 break 135 136 utils.configure_aps(aps, self._ap_spec) 137 138 aps = utils.filter_quarantined_and_config_failed_aps(aps, 139 batch_locker, job) 140 141 for ap in aps: 142 # http://crbug.com/306687 143 if ap.ssid == None: 144 logging.error('The SSID was not set for the AP:%s', 145 ap) 146 147 healthy_dut = utils.is_dut_healthy(client, ap) 148 149 if not healthy_dut: 150 logging.error('DUT is not healthy, rebooting.') 151 batch_locker.unlock_and_reclaim_aps() 152 break 153 154 networks = utils.return_available_networks( 155 ap, capturer, job, self._ap_spec) 156 157 if networks is None: 158 # If scan returned no networks, iw scan failed. 159 # Reboot the packet capturer device and 160 # reconfigure the capturer. 161 batch_locker.unlock_and_reclaim_ap(ap.host_name) 162 logging.error('Packet capture is not healthy, ' 163 'rebooting.') 164 capturer.host.reboot() 165 capturer = site_linux_system.LinuxSystem( 166 capture_host, {},'packet_capturer') 167 continue 168 if networks == list(): 169 # Packet capturer did not find the SSID in scan or 170 # there was a security mismatch. 171 utils.release_ap(ap, batch_locker) 172 continue 173 174 assoc_params = ap.get_association_parameters() 175 176 if not utils.is_conn_worker_healthy( 177 conn_worker, ap, assoc_params, job): 178 utils.release_ap( 179 ap, batch_locker) 180 continue 181 182 name = ap.name 183 kernel_ver = self._host.get_kernel_ver() 184 firmware_ver = utils.get_firmware_ver(self._host) 185 if not firmware_ver: 186 firmware_ver = "Unknown" 187 188 debug_dict = {'+++PARSE DATA+++': '+++PARSE DATA+++', 189 'SSID': ap._ssid, 190 'DUT': client.wifi_mac, 191 'AP Info': ap.name, 192 'kernel_version': kernel_ver, 193 'wifi_firmware_version': firmware_ver} 194 debug_string = pprint.pformat(debug_dict) 195 196 logging.info('Waiting %d seconds for the AP dhcp ' 197 'server', ap.dhcp_delay) 198 time.sleep(ap.dhcp_delay) 199 200 result = job.run_test(self._test, 201 capturer=capturer, 202 capturer_frequency=networks[0].frequency, 203 capturer_ht_type=networks[0].ht, 204 host=self._host, 205 assoc_params=assoc_params, 206 client=client, 207 tries=tries, 208 debug_info=debug_string, 209 # Copy all logs from the system 210 disabled_sysinfo=disabled_sysinfo, 211 conn_worker=conn_worker, 212 tag=ap.ssid if conn_worker is None else 213 '%s.%s' % (conn_worker.name, ap.ssid)) 214 215 utils.release_ap(ap, batch_locker) 216 217 if conn_worker is not None: 218 conn_worker.cleanup() 219 220 if not healthy_dut: 221 continue 222 223 batch_locker.unlock_aps() 224 225 capturer.close() 226 227 factory = ap_configurator_factory.APConfiguratorFactory( 228 ap_constants.AP_TEST_TYPE_CHAOS) 229 factory.turn_off_all_routers([]) 230