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 67 with host_lock_manager.HostsLockedBy(lock_manager): 68 capture_host = utils.allocate_packet_capturer(lock_manager) 69 70 # Cleanup and reboot packet capturer before the test. 71 utils.sanitize_client(capture_host) 72 capturer = site_linux_system.LinuxSystem(capture_host, {}, 73 'packet_capturer') 74 75 # Run iw scan and abort if more than allowed number of APs are up. 76 iw_command = iw_runner.IwRunner(capture_host) 77 start_time = time.time() 78 logging.info('Performing a scan with a max timeout of 30 seconds.') 79 capture_interface = 'wlan0' 80 capturer_info = capture_host.run('cat /etc/lsb-release', 81 ignore_status=True, timeout=5).stdout 82 if 'whirlwind' in capturer_info: 83 # Use the dual band aux radio for scanning networks. 84 capture_interface = 'wlan2' 85 while time.time() - start_time <= ap_constants.MAX_SCAN_TIMEOUT: 86 networks = iw_command.scan(capture_interface) 87 if networks is None: 88 if (time.time() - start_time == 89 ap_constants.MAX_SCAN_TIMEOUT): 90 raise error.TestError( 91 'Packet capturer is not responding to scans. Check' 92 'device and re-run test') 93 continue 94 elif len(networks) < ap_constants.MAX_SSID_COUNT: 95 break 96 elif len(networks) >= ap_constants.MAX_SSID_COUNT: 97 raise error.TestError( 98 'Probably someone is already running a ' 99 'chaos test?!') 100 101 if conn_worker is not None: 102 work_client_machine = utils.allocate_packet_capturer( 103 lock_manager, hostname=work_client_hostname) 104 conn_worker.prepare_work_client(work_client_machine) 105 106 batch_locker = ap_batch_locker.ApBatchLocker( 107 lock_manager, self._ap_spec, 108 ap_test_type=ap_constants.AP_TEST_TYPE_CHAOS) 109 110 while batch_locker.has_more_aps(): 111 # Work around for CrOS devices only:crbug.com/358716 112 utils.sanitize_client(self._host) 113 healthy_dut = True 114 115 with contextlib.closing(wifi_client.WiFiClient( 116 hosts.create_host( 117 { 118 'hostname' : self._host.hostname, 119 'afe_host' : self._host._afe_host, 120 'host_info_store' : 121 self._host.host_info_store, 122 }, 123 host_class=self._host.__class__, 124 ), 125 './debug', 126 False, 127 )) as client: 128 129 aps = batch_locker.get_ap_batch(batch_size=batch_size) 130 if not aps: 131 logging.info('No more APs to test.') 132 break 133 134 utils.configure_aps(aps, self._ap_spec) 135 136 aps = utils.filter_quarantined_and_config_failed_aps(aps, 137 batch_locker, job) 138 139 for ap in aps: 140 # http://crbug.com/306687 141 if ap.ssid == None: 142 logging.error('The SSID was not set for the AP:%s', 143 ap) 144 145 healthy_dut = utils.is_dut_healthy(client, ap) 146 147 if not healthy_dut: 148 logging.error('DUT is not healthy, rebooting.') 149 batch_locker.unlock_and_reclaim_aps() 150 break 151 152 networks = utils.return_available_networks( 153 ap, capturer, job, self._ap_spec) 154 155 if networks is None: 156 # If scan returned no networks, iw scan failed. 157 # Reboot the packet capturer device and 158 # reconfigure the capturer. 159 batch_locker.unlock_and_reclaim_ap(ap.host_name) 160 logging.error('Packet capture is not healthy, ' 161 'rebooting.') 162 capturer.host.reboot() 163 capturer = site_linux_system.LinuxSystem( 164 capture_host, {},'packet_capturer') 165 continue 166 if networks == list(): 167 # Packet capturer did not find the SSID in scan or 168 # there was a security mismatch. 169 utils.release_ap(ap, batch_locker) 170 continue 171 172 assoc_params = ap.get_association_parameters() 173 174 if not utils.is_conn_worker_healthy( 175 conn_worker, ap, assoc_params, job): 176 utils.release_ap( 177 ap, batch_locker) 178 continue 179 180 name = ap.name 181 kernel_ver = self._host.get_kernel_ver() 182 firmware_ver = utils.get_firmware_ver(self._host) 183 if not firmware_ver: 184 firmware_ver = "Unknown" 185 186 debug_dict = {'+++PARSE DATA+++': '+++PARSE DATA+++', 187 'SSID': ap._ssid, 188 'DUT': client.wifi_mac, 189 'AP Info': ap.name, 190 'kernel_version': kernel_ver, 191 'wifi_firmware_version': firmware_ver} 192 debug_string = pprint.pformat(debug_dict) 193 194 logging.info('Waiting %d seconds for the AP dhcp ' 195 'server', ap.dhcp_delay) 196 time.sleep(ap.dhcp_delay) 197 198 result = job.run_test(self._test, 199 capturer=capturer, 200 capturer_frequency=networks[0].frequency, 201 capturer_ht_type=networks[0].width, 202 host=self._host, 203 assoc_params=assoc_params, 204 client=client, 205 tries=tries, 206 debug_info=debug_string, 207 # Copy all logs from the system 208 disabled_sysinfo=disabled_sysinfo, 209 conn_worker=conn_worker, 210 tag=ap.ssid if conn_worker is None else 211 '%s.%s' % (conn_worker.name, ap.ssid)) 212 213 utils.release_ap(ap, batch_locker) 214 215 if conn_worker is not None: 216 conn_worker.cleanup() 217 218 if not healthy_dut: 219 continue 220 221 batch_locker.unlock_aps() 222 223 capturer.close() 224 225 factory = ap_configurator_factory.APConfiguratorFactory( 226 ap_constants.AP_TEST_TYPE_CHAOS) 227 factory.turn_off_all_routers([]) 228