test_droid.py revision 5d7a7098589fe52703cda3788ce889588c42e7e4
1#!/usr/bin/python
2# Copyright 2015 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6import argparse
7import os
8import sys
9
10import logging
11# Turn the logging level to INFO before importing other autotest
12# code, to avoid having failed import logging messages confuse the
13# test_droid user.
14logging.basicConfig(level=logging.INFO)
15
16
17import common
18# Unfortunately, autotest depends on external packages for assorted
19# functionality regardless of whether or not it is needed in a particular
20# context.
21# Since we can't depend on people to import these utilities in any principled
22# way, we dynamically download code before any autotest imports.
23try:
24    import chromite.lib.terminal  # pylint: disable=unused-import
25    import django.http  # pylint: disable=unused-import
26except ImportError:
27    # Ensure the chromite site-package is installed.
28    import subprocess
29    build_externals_path = os.path.join(
30            os.path.dirname(os.path.dirname(os.path.realpath(__file__))),
31            'utils', 'build_externals.py')
32    subprocess.check_call([build_externals_path, 'chromiterepo', 'django'])
33    # Restart the script so python now finds the autotest site-packages.
34    sys.exit(os.execv(__file__, sys.argv))
35
36from autotest_lib.client.common_lib import utils
37from autotest_lib.server.hosts import adb_host
38from autotest_lib.site_utils import test_runner_utils
39from autotest_lib.site_utils import tester_feedback
40
41
42def parse_arguments(argv):
43    """
44    Parse command line arguments
45
46    @param argv: argument list to parse
47
48    @returns:    parsed arguments
49
50    @raises SystemExit if arguments are malformed, or required arguments
51            are not present.
52    """
53    return _parse_arguments_internal(argv)[0]
54
55
56def _parse_arguments_internal(argv):
57    """
58    Parse command line arguments
59
60    @param argv: argument list to parse
61
62    @returns:    tuple of parsed arguments and argv suitable for remote runs
63
64    @raises SystemExit if arguments are malformed, or required arguments
65            are not present.
66    """
67
68    parser = argparse.ArgumentParser(description='Run remote tests.')
69
70    parser.add_argument('-s', '--serials', metavar='SERIALS',
71                        help='Comma separate list of device serials under '
72                             'test.')
73    parser.add_argument('-r', '--remote', metavar='REMOTE',
74                        default='localhost',
75                        help='hostname[:port] if the ADB device is connected '
76                             'to a remote machine. Ensure this workstation '
77                             'is configured for passwordless ssh access as '
78                             'users "root" or "adb"')
79    parser.add_argument('-i', '--interactive', action='store_true',
80                        help='Enable interactive feedback requests from tests.')
81    test_runner_utils.add_common_args(parser)
82    return parser.parse_args(argv)
83
84
85def main(argv):
86    """
87    Entry point for test_droid script.
88
89    @param argv: arguments list
90    """
91    arguments = _parse_arguments_internal(argv)
92
93    serials = arguments.serials
94    if serials is None:
95        result = utils.run(['adb', 'devices'])
96        devices = adb_host.ADBHost.parse_device_serials(result.stdout)
97        if len(devices) != 1:
98            logging.error('could not detect exactly one device; please select '
99                          'one with -s: %s', devices)
100            return 1
101        serials = devices[0]
102
103    results_directory = test_runner_utils.create_results_directory(
104            arguments.results_dir)
105    arguments.results_dir = results_directory
106
107    autotest_path = os.path.dirname(os.path.dirname(
108            os.path.realpath(__file__)))
109    site_utils_path = os.path.join(autotest_path, 'site_utils')
110    realpath = os.path.realpath(__file__)
111    site_utils_path = os.path.realpath(site_utils_path)
112    host_attributes = {'serials' : serials,
113                       'os_type' : 'android'}
114
115    fb_service = None
116    try:
117        # Start the feedback service if needed.
118        if arguments.interactive:
119            fb_service = tester_feedback.FeedbackService()
120            fb_service.start()
121
122            if arguments.args:
123                arguments.args += ' '
124            else:
125                arguments.args = ''
126            arguments.args += (
127                    'feedback=interactive feedback_args=localhost:%d' %
128                    fb_service.server_port)
129
130        return test_runner_utils.perform_run_from_autotest_root(
131                    autotest_path, argv, arguments.tests, arguments.remote,
132                    args=arguments.args, ignore_deps=not arguments.enforce_deps,
133                    results_directory=results_directory,
134                    iterations=arguments.iterations,
135                    fast_mode=arguments.fast_mode, debug=arguments.debug,
136                    host_attributes=host_attributes, pretend=arguments.pretend)
137    finally:
138        if fb_service is not None:
139            fb_service.stop()
140
141
142if __name__ == '__main__':
143    sys.exit(main(sys.argv[1:]))
144