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