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 23from autotest_lib.server.hosts import adb_host 24 25 26class 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( 128 { 129 'hostname' : self._host.hostname, 130 'afe_host' : self._host._afe_host, 131 'host_info_store' : 132 self._host.host_info_store, 133 }, 134 host_class=self._host.__class__, 135 ), 136 './debug', 137 False, 138 )) as client: 139 140 aps = batch_locker.get_ap_batch(batch_size=batch_size) 141 if not aps: 142 logging.info('No more APs to test.') 143 break 144 145 utils.configure_aps(aps, self._ap_spec) 146 147 aps = utils.filter_quarantined_and_config_failed_aps(aps, 148 batch_locker, job) 149 150 for ap in aps: 151 # http://crbug.com/306687 152 if ap.ssid == None: 153 logging.error('The SSID was not set for the AP:%s', 154 ap) 155 156 healthy_dut = utils.is_dut_healthy(client, ap) 157 158 if not healthy_dut: 159 logging.error('DUT is not healthy, rebooting.') 160 batch_locker.unlock_and_reclaim_aps() 161 break 162 163 networks = utils.return_available_networks( 164 ap, capturer, job, self._ap_spec) 165 166 if networks is None: 167 # If scan returned no networks, iw scan failed. 168 # Reboot the packet capturer device and 169 # reconfigure the capturer. 170 batch_locker.unlock_and_reclaim_ap(ap.host_name) 171 logging.error('Packet capture is not healthy, ' 172 'rebooting.') 173 capturer.host.reboot() 174 capturer = site_linux_system.LinuxSystem( 175 capture_host, {},'packet_capturer') 176 continue 177 if networks == list(): 178 # Packet capturer did not find the SSID in scan or 179 # there was a security mismatch. 180 utils.release_ap(ap, batch_locker) 181 continue 182 183 assoc_params = ap.get_association_parameters() 184 185 if not utils.is_conn_worker_healthy( 186 conn_worker, ap, assoc_params, job): 187 utils.release_ap( 188 ap, batch_locker) 189 continue 190 191 name = ap.name 192 kernel_ver = self._host.get_kernel_ver() 193 firmware_ver = utils.get_firmware_ver(self._host) 194 if not firmware_ver: 195 firmware_ver = "Unknown" 196 197 debug_dict = {'+++PARSE DATA+++': '+++PARSE DATA+++', 198 'SSID': ap._ssid, 199 'DUT': client.wifi_mac, 200 'AP Info': ap.name, 201 'kernel_version': kernel_ver, 202 'wifi_firmware_version': firmware_ver} 203 debug_string = pprint.pformat(debug_dict) 204 205 logging.info('Waiting %d seconds for the AP dhcp ' 206 'server', ap.dhcp_delay) 207 time.sleep(ap.dhcp_delay) 208 209 result = job.run_test(self._test, 210 capturer=capturer, 211 capturer_frequency=networks[0].frequency, 212 capturer_ht_type=networks[0].ht, 213 host=self._host, 214 assoc_params=assoc_params, 215 client=client, 216 tries=tries, 217 debug_info=debug_string, 218 # Copy all logs from the system 219 disabled_sysinfo=disabled_sysinfo, 220 conn_worker=conn_worker, 221 tag=ap.ssid if conn_worker is None else 222 '%s.%s' % (conn_worker.name, ap.ssid)) 223 224 utils.release_ap(ap, batch_locker) 225 226 if conn_worker is not None: 227 conn_worker.cleanup() 228 229 if not healthy_dut: 230 continue 231 232 batch_locker.unlock_aps() 233 234 capturer.close() 235 236 factory = ap_configurator_factory.APConfiguratorFactory( 237 test_type) 238 factory.turn_off_all_routers([]) 239