setup_job.py revision 80f0078376f052d74af7bdae2975e577b0c7de7a
1# Copyright 2007 Google Inc. Released under the GPL v2
2#
3# Eric Li <ericli@google.com>
4
5import logging, os, pickle, re, sys
6import common
7
8from autotest_lib.client.bin import client_logging_config
9from autotest_lib.client.bin import job as client_job
10from autotest_lib.client.common_lib import base_job
11from autotest_lib.client.common_lib import error
12from autotest_lib.client.common_lib import logging_manager
13from autotest_lib.client.common_lib import packages
14
15
16class setup_job(client_job.job):
17    """
18    setup_job is a job which runs client test setup() method at server side.
19
20    This job is used to pre-setup client tests when development toolchain is not
21    available at client.
22    """
23
24    def __init__(self, options):
25        """
26        Since setup_job is a client job but run on a server, it takes no control
27        file as input. So client_job.__init__ is by-passed.
28
29        @param options: an object passed in from command line OptionParser.
30                        See all options defined on client/bin/autotest.
31        """
32        base_job.base_job.__init__(self, options=options)
33        logging_manager.configure_logging(
34            client_logging_config.ClientLoggingConfig(),
35            results_dir=self.resultdir,
36            verbose=options.verbose)
37        self._cleanup_results_dir()
38        self.pkgmgr = packages.PackageManager(
39            self.autodir, run_function_dargs={'timeout':3600})
40
41
42def load_all_client_tests(options):
43    """
44    Load and instantiate all client tests.
45
46    This function is inspired from runtest() on client/common_lib/test.py.
47
48    @param options: an object passed in from command line OptionParser.
49                    See all options defined on client/bin/autotest.
50
51    @return a tuple containing the list of all instantiated tests and
52            a list of tests that failed to instantiate.
53    """
54
55    local_namespace = locals().copy()
56    global_namespace = globals().copy()
57
58    all_tests = []
59    broken_tests = []
60    for test_base_dir in ['tests', 'site_tests']:
61        testdir = os.path.join(os.environ['AUTODIR'], test_base_dir)
62        for test_name in os.listdir(testdir):
63            job = setup_job(options=options)
64            testbindir = os.path.join(testdir, test_name)
65            local_namespace['testbindir'] = testbindir
66
67            outputdir = os.path.join(job.resultdir, test_name)
68            try:
69                os.makedirs(outputdir)
70            except OSError:
71                pass
72
73            local_namespace['job'] = job
74            local_namespace['outputdir'] = outputdir
75
76            sys.path.insert(0, testbindir)
77            try:
78                try:
79                    exec("import %s" % test_name, local_namespace,
80                         global_namespace)
81                    exec("auto_test = %s.%s(job, testbindir, outputdir)" %
82                         (test_name, test_name), local_namespace,
83                         global_namespace)
84                    client_test = global_namespace['auto_test']
85                    all_tests.append(client_test)
86                except ImportError, e:
87                    # skips error if test is control file without python test
88                    if re.search(test_name, str(e)):
89                        pass
90                    # give the user a warning if there is an import error.
91                    else:
92                        logging.warning("%s import error: %s.  Skipping %s" \
93                            % (test_name, e, test_name))
94            except Exception, e:
95                # Log other errors (e.g., syntax errors) and collect the test.
96                logging.error("%s: %s", test_name, e)
97                broken_tests.append(test_name)
98            finally:
99                sys.path.pop(0) # pop up testbindir
100    return all_tests, broken_tests
101
102
103def setup_tests(options):
104    """
105    Load and instantiate all client tests.
106
107    This function is inspired from runtest() on client/common_lib/test.py.
108
109    @param options: an object passed in from command line OptionParser.
110                    See all options defined on client/bin/autotest.
111    """
112
113    assert options.client_test_setup, 'Specify prebuild client tests on the ' \
114                                      'command line.'
115
116    requested_tests = options.client_test_setup.split(',')
117    candidates, broken_tests = load_all_client_tests(options)
118
119    failed_tests = []
120    if 'all' in requested_tests:
121        need_to_setup = candidates
122        failed_tests += broken_tests
123    else:
124        need_to_setup = []
125        for candidate in candidates:
126            if candidate.__class__.__name__ in requested_tests:
127                need_to_setup.append(candidate)
128        for broken_test in broken_tests:
129            if broken_test in requested_tests:
130                failed_tests.append(broken_test)
131
132    if need_to_setup:
133        cwd = os.getcwd()
134        os.chdir(need_to_setup[0].job.clientdir)
135        os.system('tools/make_clean')
136        os.chdir(cwd)
137    elif not failed_tests:
138        logging.error('### No test setup candidates ###')
139        raise error.AutoservError('No test setup candidates.')
140
141    for setup_test in need_to_setup:
142        test_name = setup_test.__class__.__name__
143        try:
144            outputdir = os.path.join(setup_test.job.resultdir, test_name)
145            try:
146                os.makedirs(outputdir)
147                os.chdir(outputdir)
148            except OSError:
149                pass
150            logging.info('setup %s.' % test_name)
151            setup_test.setup()
152            # Touch .version file under src to prevent further setup on client
153            # host. See client/common_lib/utils.py update_version()
154            if os.path.exists(setup_test.srcdir):
155                versionfile = os.path.join(setup_test.srcdir, '.version')
156                pickle.dump(setup_test.version, open(versionfile, 'w'))
157        except Exception, err:
158            logging.error(err)
159            failed_tests.append(test_name)
160
161    logging.info('############################# SUMMARY '
162                 '#############################')
163
164    # Print out tests that failed
165    if failed_tests:
166        logging.info('Finished setup -- The following tests failed')
167        for failed_test in failed_tests:
168            logging.info(failed_test)
169    else:
170        logging.info('Finished setup -- All tests built successfully')
171    logging.info('######################### END SUMMARY '
172                 '##############################')
173    if failed_tests:
174        raise error.AutoservError('Finished setup with errors.')
175