[autotest] test_droid V1.

This CL introduces test_droid, a script to launch autotest
tests against local Android DUTs connected to the host
computer via USB.

Much of the logic is similar to test_that, so this has all
been pulled into a new script test_utils.py

Pending work:

* Moving of generate_test_report to somewhere it is accesible
  outside of the chroot.
* Add in support for remote adb hosts (i.e. the DUT is
  connected to a remote computer).
* Sequences support.

BUG=b:25748759
TEST=./test_droid.py 7d52318 brillo_WhitelistedGtests
CQ-DEPEND=CL:315230

Change-Id: Idab3805f7921173fbc706354b322f37244240fa2
Reviewed-on: https://chromium-review.googlesource.com/314870
Commit-Ready: Simran Basi <[email protected]>
Tested-by: Simran Basi <[email protected]>
Reviewed-by: Aviv Keshet <[email protected]>
diff --git a/server/autoserv_utils.py b/server/autoserv_utils.py
index 3a11cca..679418c 100644
--- a/server/autoserv_utils.py
+++ b/server/autoserv_utils.py
@@ -29,7 +29,8 @@
                              no_console_prefix=False,
                              ssh_options=None,
                              use_packaging=True,
-                             in_lab=False):
+                             in_lab=False,
+                             host_attributes=None):
     """
     Construct an autoserv command from a job or host queue entry.
 
@@ -61,6 +62,7 @@
                    environment. This information is useful as autoserv knows
                    the database is available and can make database calls such
                    as looking up host attributes at runtime.
+    @param host_attributes: Dict of host attributes to pass into autoserv.
 
     @returns The autoserv command line as a list of executable + parameters.
 
@@ -109,6 +111,9 @@
             elif control_type_value == control_data.CONTROL_TYPE.SERVER:
                 command.append('-s')
 
+    if host_attributes:
+        command += ['--host_attributes', repr(host_attributes)]
+
     if verbose:
         command.append('--verbose')
 
diff --git a/server/constants.py b/server/constants.py
index 2840370..18319c1 100644
--- a/server/constants.py
+++ b/server/constants.py
@@ -8,4 +8,4 @@
 CRASHLOGS_MARKER = '.crashjob'
 
 # Flag file to indicate the host is an adb tester.
-ANDROID_TESTER_FILEFLAG = '/mnt/stateful_partition/.android_tester'
+ANDROID_TESTER_FILEFLAG = '/mnt/stateful_partition/.android_tester'
\ No newline at end of file
diff --git a/server/hosts/adb_host.py b/server/hosts/adb_host.py
index cce602b..238cbdd 100644
--- a/server/hosts/adb_host.py
+++ b/server/hosts/adb_host.py
@@ -115,6 +115,10 @@
         """
         Check if the given host is an adb host.
 
+        If SSH connectivity can't be established, check_host will try to use
+        user 'adb' as well. If SSH connectivity still can't be established
+        then the original SSH user is restored.
+
         @param host: An ssh host representing a device.
         @param timeout: The timeout for the run command.
 
@@ -124,13 +128,16 @@
         @raises AutoservRunError: If the command failed.
         @raises AutoservSSHTimeout: Ssh connection has timed out.
         """
+        ssh_user = host.user
         try:
-            if not host.verify_ssh_user_access():
+            if not (host.hostname == 'localhost' or
+                    host.verify_ssh_user_access()):
                 host.user = 'adb'
             result = host.run(
                     'test -f %s' % server_constants.ANDROID_TESTER_FILEFLAG,
                     timeout=timeout)
         except (error.AutoservRunError, error.AutoservSSHTimeout):
+            host.user = ssh_user
             return False
         return result.exit_status == 0
 
diff --git a/server/hosts/factory.py b/server/hosts/factory.py
index 9e87012..2382df9 100644
--- a/server/hosts/factory.py
+++ b/server/hosts/factory.py
@@ -3,6 +3,7 @@
 import logging
 from contextlib import closing
 
+from autotest_lib.client.bin import local_host
 from autotest_lib.client.common_lib import error, global_config
 from autotest_lib.server import utils as server_utils
 from autotest_lib.server.hosts import cros_host, ssh_host
@@ -29,6 +30,8 @@
 # overhead in checking for less common host types.
 host_types = [cros_host.CrosHost, moblab_host.MoblabHost, sonic_host.SonicHost,
               adb_host.ADBHost,]
+OS_HOST_DICT = {'cros' : cros_host.CrosHost,
+                'android': adb_host.ADBHost}
 
 
 def _get_host_arguments():
@@ -113,8 +116,10 @@
     args['ssh_verbosity_flag'] = ssh_verbosity_flag
     args['ssh_options'] = ssh_options
 
+    if hostname == 'localhost':
+        connectivity_class = local_host.LocalHost
     # by default assume we're using SSH support
-    if SSH_ENGINE == 'paramiko':
+    elif SSH_ENGINE == 'paramiko':
         from autotest_lib.server.hosts import paramiko_host
         connectivity_class = paramiko_host.ParamikoHost
     elif SSH_ENGINE == 'raw_ssh':
@@ -124,12 +129,13 @@
                                   "value of the configuration key 'ssh_engine' "
                                   "on autotest's global_config.ini file." %
                                   SSH_ENGINE)
-
-    if not host_class:
+    host_attributes = args.get('host_attributes', {})
+    host_class = host_class or OS_HOST_DICT.get(host_attributes.get('os_type'))
+    if host_class:
+        classes = [host_class, connectivity_class]
+    else:
         classes = [_detect_host(connectivity_class, hostname, **args),
                    connectivity_class]
-    else:
-        classes = [host_class, connectivity_class]
 
     # create a custom host class for this machine and return an instance of it
     host_class = type("%s_host" % hostname, tuple(classes), {})