autotest: Adds support for cast client.

Cast OS requires some minor changes/refactoring to
WiFiClient, WpaCliProxy, and the addition of a new
interface type.

BUG=b:33277079
TEST=Local sample tests which covers connect,
disconnect, connectivity tests, and interface
methods/properties. Ran a local test
(network_WiFi_SimpleConnect) with a cros client
as the DUT to ensure no breakage there.

Change-Id: I80b2d47be26eef963d442ad3c54406c39a20b97a
Reviewed-on: https://chromium-review.googlesource.com/488168
Commit-Ready: Dane Pollock <danepollock@google.com>
Tested-by: Dane Pollock <danepollock@google.com>
Reviewed-by: Laurence Goodby <lgoodby@chromium.org>
Reviewed-by: Brian Norris <briannorris@chromium.org>
diff --git a/server/cros/network/wifi_client.py b/server/cros/network/wifi_client.py
index d222da6..5f1226b 100644
--- a/server/cros/network/wifi_client.py
+++ b/server/cros/network/wifi_client.py
@@ -23,6 +23,7 @@
 from autotest_lib.server import site_linux_system
 from autotest_lib.server.cros.network import wpa_cli_proxy
 from autotest_lib.server.hosts import adb_host
+from autotest_lib.server.hosts import cast_os_host
 
 # Wake-on-WiFi feature strings
 WAKE_ON_WIFI_NONE = 'none'
@@ -55,6 +56,18 @@
 ANDROID_LOCAL_DEBUG_DIR_FMT = 'android_debug_%s'
 
 
+def _is_android_host(host):
+    return host.get_os_type() == adb_host.OS_TYPE_ANDROID
+
+
+def _is_brillo_host(host):
+    return host.get_os_type() == adb_host.OS_TYPE_BRILLO
+
+
+def _is_eureka_host(host):
+    return host.get_os_type() == cast_os_host.OS_TYPE_CAST_OS
+
+
 def install_android_xmlrpc_server(host, server_port):
     """Install Android XMLRPC server script on |host|.
 
@@ -91,12 +104,12 @@
     # This is the default port for shill xmlrpc server.
     server_port = constants.SHILL_XMLRPC_SERVER_PORT
 
-    if host.get_os_type() == adb_host.OS_TYPE_BRILLO:
+    if _is_brillo_host(host):
         xmlrpc_server_command = constants.SHILL_BRILLO_XMLRPC_SERVER_COMMAND
         log_path = SHILL_BRILLO_XMLRPC_LOG_PATH
         command_name = constants.SHILL_BRILLO_XMLRPC_SERVER_CLEANUP_PATTERN
         rpc_server_host = host
-    elif host.get_os_type() == adb_host.OS_TYPE_ANDROID:
+    elif _is_android_host(host):
         if not host.adb_serial:
             raise error.TestFail('No serial number detected')
         debug_dir = ANDROID_XMLRPC_DEBUG_DIR_FMT % host.adb_serial
@@ -156,8 +169,8 @@
     MAX_SERVICE_GONE_TIMEOUT_SECONDS = 60
 
     # List of interface names we won't consider for use as "the" WiFi interface
-    # on Android hosts.
-    WIFI_IF_BLACKLIST = ['p2p0']
+    # on Android or CastOS hosts.
+    WIFI_IF_BLACKLIST = ['p2p0', 'wfd0']
 
     UNKNOWN_BOARD_TYPE = 'unknown'
 
@@ -361,7 +374,8 @@
         self._result_dir = result_dir
         self._conductive = None
 
-        if self.host.get_os_type() == adb_host.OS_TYPE_ANDROID and use_wpa_cli:
+        if ((_is_android_host(self.host) or _is_eureka_host(self.host)) and
+            use_wpa_cli):
             # Look up the WiFi device (and its MAC) on the client.
             devs = self.iw_runner.list_interfaces(desired_if_type='managed')
             devs = [dev for dev in devs
@@ -378,7 +392,7 @@
                     self.host, self._wifi_if)
             self._wpa_cli_proxy = self._shill_proxy
         else:
-            if self.host.get_os_type() == adb_host.OS_TYPE_ANDROID:
+            if _is_android_host(self.host):
                 adb_utils.install_apk_from_build(
                         self.host,
                         server_constants.SL4A_APK,
@@ -470,8 +484,8 @@
         """
         # Make no assertions about ADBHost support.  We don't use an XMLRPC
         # proxy with those hosts anyway.
-        supported = (isinstance(self.host, adb_host.ADBHost) or
-                     method_name in self._shill_proxy.system.listMethods())
+        supported = (_is_android_host(self.host) or _is_eureka_host(self.host)
+                     or method_name in self._shill_proxy.system.listMethods())
         if not supported:
             logging.warning('%s() is not supported on older images',
                             method_name)
@@ -528,7 +542,7 @@
 
         @param local_save_dir_prefix Used as a prefix for local save directory.
         """
-        if self.host.get_os_type() == adb_host.OS_TYPE_ANDROID:
+        if _is_android_host(self.host):
             # First capture the bugreport to the test station
             self.shill.collect_debug_info(local_save_dir_prefix)
             # Now copy the file over from test station to the server.
diff --git a/server/cros/network/wpa_cli_proxy.py b/server/cros/network/wpa_cli_proxy.py
index 1fdcc86..d4db9ef 100644
--- a/server/cros/network/wpa_cli_proxy.py
+++ b/server/cros/network/wpa_cli_proxy.py
@@ -32,7 +32,7 @@
     ANDROID_CMD_FORMAT = '/system/bin/wpa_cli IFNAME={0[ifname]} {0[cmd]}'
     BRILLO_CMD_FORMAT = 'su system /system/bin/wpa_cli -i{0[ifname]} -p/data/misc/wifi/sockets {0[cmd]}'
     CROS_CMD_FORMAT = 'su wpa -s /bin/bash -c "/usr/bin/wpa_cli {0[cmd]}"'
-
+    CAST_CMD_FORMAT = '/system/bin/wpa_cli {0[cmd]}'
 
 
     def __init__(self, host, wifi_if):
@@ -48,6 +48,8 @@
             self._wpa_cli_cmd_format = self.BRILLO_CMD_FORMAT
         elif host.get_os_type() == 'cros':
             self._wpa_cli_cmd_format = self.CROS_CMD_FORMAT
+        elif host.get_os_type() == 'cast_os':
+            self._wpa_cli_cmd_format = self.CAST_CMD_FORMAT
 
 
     def _add_network(self, ssid):
diff --git a/server/hosts/cast_os_host.py b/server/hosts/cast_os_host.py
new file mode 100644
index 0000000..f663f1c
--- /dev/null
+++ b/server/hosts/cast_os_host.py
@@ -0,0 +1,28 @@
+# Copyright 2017 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.
+
+"""Implements a Cast OS host type."""
+
+from autotest_lib.server.hosts import ssh_host
+
+OS_TYPE_CAST_OS = 'cast_os'
+
+
+class CastOSHost(ssh_host.SSHHost):
+    """Implements a Cast OS host type."""
+
+
+    def get_os_type(self):
+        """Returns the host OS descriptor."""
+        return OS_TYPE_CAST_OS
+
+
+    def get_wifi_interface_name(self):
+        """Gets the WiFi interface name."""
+        return self.run('getprop wifi.interface').stdout.rstrip()
+
+
+    @property
+    def is_client_install_supported(self):
+        return False