• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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