# Copyright 2015 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import logging

import common
from autotest_lib.client.common_lib import error
from autotest_lib.client.common_lib import global_config
from autotest_lib.client.common_lib import utils
from autotest_lib.client.common_lib.cros.network import iw_runner
from autotest_lib.server import afe_utils
from autotest_lib.server import test
from autotest_lib.server.brillo import host_utils


class brillo_WifiInterfaceTest(test.test):
    """Verify that a Brillo device has its wifi properly configured."""
    version = 1

    def get_ifconfig_dict(self, ifconfig_output):
        """Convert output of ifconfig into a dictionary.

        @param ifconfig_output: List of ifconfig output lines.

        @return Dictionary mapping interface names (e.g. 'wlan0') to their list
                of stripped output lines.
        """
        curr_iface = None
        ifconfig_dict = {}
        for line in ifconfig_output:
            if curr_iface is None:
                curr_iface, line = line.split(None, 1)
                ifconfig_dict[curr_iface] = []

            line = line.strip()
            if line:
                ifconfig_dict[curr_iface].append(line)
            else:
                curr_iface = None

        return ifconfig_dict


    def run_once(self, host=None, ssid=None, passphrase=None, wifi_iface=None,
                 wifi_ssid=None):
        """Check that a given wifi interface is properly configured.

        @param host: a host object representing the DUT.
        @param ssid: A string representing the ssid to connect to.
        @param passphrase: A string representing the passphrase to the ssid.
        @param wifi_iface: Name of the wifi interface to test; None means we'll
                           try to detect at least one that works.
        @param wifi_ssid: Name of the SSID we want the interface to be
                          connected to; None means any.

        @raise TestFail: The test failed.
        """
        self.host = host
        if afe_utils.host_in_lab(host):
            ssid = utils.get_wireless_ssid(host.hostname)
            passphrase = global_config.global_config.get_config_value(
                    'CLIENT', 'wireless_password', default=None)
        with host_utils.connect_to_ssid(host, ssid, passphrase):
            err_iface = ('No interface is' if wifi_iface is None
                          else 'Interface %s is not' % wifi_iface)

            # First check link status and SSID.
            iw = iw_runner.IwRunner(remote_host=host)
            active_ifaces = []
            try:
                iw_ifaces = [iface_tuple.if_name
                             for iface_tuple in iw.list_interfaces()]
                if wifi_iface is not None:
                    if wifi_iface not in iw_ifaces:
                        raise error.TestFail(
                                'Interface %s not listed by iw' % wifi_iface)
                    test_ifaces = [wifi_iface]
                else:
                    test_ifaces = iw_ifaces

                for iface in test_ifaces:
                    iface_ssid = iw.get_link_value(iface, 'SSID')
                    if (iface_ssid is not None and
                        (wifi_ssid is None or iface_ssid == wifi_ssid)):
                        active_ifaces.append(iface)
            except error.GenericHostRunError:
                raise error.TestFail('Failed to run iw')

            if not active_ifaces:
                err_ssid = 'any SSID' if wifi_ssid is None else ('SSID ' +
                                                                 wifi_ssid)
                raise error.TestFail('%s connected to %s' % (err_iface,
                                                             err_ssid))

            logging.info('Active wifi interfaces: %s', ', '.join(active_ifaces))

            # Then check IPv4 connectivity.
            try:
                ifconfig_output = host.run_output('ifconfig').splitlines()
            except error.GenericHostRunError:
                raise error.TestFail('Failed to run ifconfig')

            ifconfig_dict = self.get_ifconfig_dict(ifconfig_output)
            connected_ifaces = [iface for iface in active_ifaces
                                if any(['inet addr:' in line
                                        for line in ifconfig_dict.get(iface,
                                                                      [])])]
            if not connected_ifaces:
                raise error.TestFail('%s IPv4 connected' % err_iface)

            logging.info('IPv4 connected wifi interfaces: %s',
                         ', '.join(connected_ifaces))
