xref: /aosp_15_r20/external/autotest/client/bin/setup_job.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1*9c5db199SXin Li# Lint as: python2, python3
2*9c5db199SXin Li# Copyright 2007 Google Inc. Released under the GPL v2
3*9c5db199SXin Li#
4*9c5db199SXin Li# Eric Li <[email protected]>
5*9c5db199SXin Li
6*9c5db199SXin Liimport logging, os, pickle, re, sys
7*9c5db199SXin Liimport common
8*9c5db199SXin Li
9*9c5db199SXin Lifrom autotest_lib.client.bin import job as client_job
10*9c5db199SXin Lifrom autotest_lib.client.common_lib import base_job
11*9c5db199SXin Lifrom autotest_lib.client.common_lib import error
12*9c5db199SXin Lifrom autotest_lib.client.common_lib import logging_manager
13*9c5db199SXin Lifrom autotest_lib.client.common_lib import packages
14*9c5db199SXin Li
15*9c5db199SXin Li
16*9c5db199SXin Liclass setup_job(client_job.job):
17*9c5db199SXin Li    """
18*9c5db199SXin Li    setup_job is a job which runs client test setup() method at server side.
19*9c5db199SXin Li
20*9c5db199SXin Li    This job is used to pre-setup client tests when development toolchain is not
21*9c5db199SXin Li    available at client.
22*9c5db199SXin Li    """
23*9c5db199SXin Li
24*9c5db199SXin Li    def __init__(self, options):
25*9c5db199SXin Li        """
26*9c5db199SXin Li        Since setup_job is a client job but run on a server, it takes no control
27*9c5db199SXin Li        file as input. So client_job.__init__ is by-passed.
28*9c5db199SXin Li
29*9c5db199SXin Li        @param options: an object passed in from command line OptionParser.
30*9c5db199SXin Li                        See all options defined on client/bin/autotest.
31*9c5db199SXin Li        """
32*9c5db199SXin Li        base_job.base_job.__init__(self, options=options)
33*9c5db199SXin Li        self._cleanup_debugdir_files()
34*9c5db199SXin Li        self._cleanup_results_dir()
35*9c5db199SXin Li        self.machine_dict_list = [{'hostname' : options.hostname}]
36*9c5db199SXin Li        # Client side tests should always run the same whether or not they are
37*9c5db199SXin Li        # running in the lab.
38*9c5db199SXin Li        self.in_lab = False
39*9c5db199SXin Li        self.pkgmgr = packages.PackageManager(
40*9c5db199SXin Li            self.autodir, run_function_dargs={'timeout':3600})
41*9c5db199SXin Li
42*9c5db199SXin Li
43*9c5db199SXin Lidef init_test(options, testdir):
44*9c5db199SXin Li    """
45*9c5db199SXin Li    Instantiate a client test object from a given test directory.
46*9c5db199SXin Li
47*9c5db199SXin Li    @param options Command line options passed in to instantiate a setup_job
48*9c5db199SXin Li                   which associates with this test.
49*9c5db199SXin Li    @param testdir The test directory.
50*9c5db199SXin Li    @returns A test object or None if failed to instantiate.
51*9c5db199SXin Li    """
52*9c5db199SXin Li
53*9c5db199SXin Li    locals_dict = locals().copy()
54*9c5db199SXin Li    globals_dict = globals().copy()
55*9c5db199SXin Li
56*9c5db199SXin Li    locals_dict['testdir'] = testdir
57*9c5db199SXin Li
58*9c5db199SXin Li    job = setup_job(options=options)
59*9c5db199SXin Li    locals_dict['job'] = job
60*9c5db199SXin Li
61*9c5db199SXin Li    test_name = os.path.split(testdir)[-1]
62*9c5db199SXin Li    outputdir = os.path.join(job.resultdir, test_name)
63*9c5db199SXin Li    try:
64*9c5db199SXin Li        os.makedirs(outputdir)
65*9c5db199SXin Li    except OSError:
66*9c5db199SXin Li        pass
67*9c5db199SXin Li    locals_dict['outputdir'] = outputdir
68*9c5db199SXin Li
69*9c5db199SXin Li    sys.path.insert(0, testdir)
70*9c5db199SXin Li    client_test = None
71*9c5db199SXin Li    try:
72*9c5db199SXin Li        try:
73*9c5db199SXin Li            import_stmt = 'import %s' % test_name
74*9c5db199SXin Li            init_stmt = ('auto_test = %s.%s(job, testdir, outputdir)' %
75*9c5db199SXin Li                         (test_name, test_name))
76*9c5db199SXin Li            exec(import_stmt + '\n' + init_stmt, locals_dict, globals_dict)
77*9c5db199SXin Li            client_test = globals_dict['auto_test']
78*9c5db199SXin Li        except ImportError as e:
79*9c5db199SXin Li            # skips error if test is control file without python test
80*9c5db199SXin Li            if re.search(test_name, str(e)):
81*9c5db199SXin Li                pass
82*9c5db199SXin Li            # give the user a warning if there is an import error.
83*9c5db199SXin Li            else:
84*9c5db199SXin Li                logging.exception('%s import error: %s.  Skipping %s' %
85*9c5db199SXin Li                              (test_name, e, test_name))
86*9c5db199SXin Li        except Exception as e:
87*9c5db199SXin Li            # Log other errors (e.g., syntax errors) and collect the test.
88*9c5db199SXin Li            logging.exception("%s: %s", test_name, e)
89*9c5db199SXin Li    finally:
90*9c5db199SXin Li        sys.path.pop(0) # pop up testbindir
91*9c5db199SXin Li    return client_test
92*9c5db199SXin Li
93*9c5db199SXin Li
94*9c5db199SXin Lidef load_all_client_tests(options):
95*9c5db199SXin Li    """
96*9c5db199SXin Li    Load and instantiate all client tests.
97*9c5db199SXin Li
98*9c5db199SXin Li    This function is inspired from runtest() on client/common_lib/test.py.
99*9c5db199SXin Li
100*9c5db199SXin Li    @param options: an object passed in from command line OptionParser.
101*9c5db199SXin Li                    See all options defined on client/bin/autotest.
102*9c5db199SXin Li
103*9c5db199SXin Li    @return a tuple containing the list of all instantiated tests and
104*9c5db199SXin Li            a list of tests that failed to instantiate.
105*9c5db199SXin Li    """
106*9c5db199SXin Li
107*9c5db199SXin Li    local_namespace = locals().copy()
108*9c5db199SXin Li    global_namespace = globals().copy()
109*9c5db199SXin Li
110*9c5db199SXin Li    all_tests = []
111*9c5db199SXin Li    broken_tests = []
112*9c5db199SXin Li    for test_base_dir in ['tests', 'site_tests']:
113*9c5db199SXin Li        testdir = os.path.join(os.environ['AUTODIR'], test_base_dir)
114*9c5db199SXin Li        for test_name in sorted(os.listdir(testdir)):
115*9c5db199SXin Li            client_test = init_test(options, os.path.join(testdir, test_name))
116*9c5db199SXin Li            if client_test:
117*9c5db199SXin Li                all_tests.append(client_test)
118*9c5db199SXin Li            else:
119*9c5db199SXin Li                broken_tests.append(test_name)
120*9c5db199SXin Li    return all_tests, broken_tests
121*9c5db199SXin Li
122*9c5db199SXin Li
123*9c5db199SXin Lidef setup_test(client_test):
124*9c5db199SXin Li    """
125*9c5db199SXin Li    Direct invoke test.setup() method.
126*9c5db199SXin Li
127*9c5db199SXin Li    @returns A boolean to represent success or not.
128*9c5db199SXin Li    """
129*9c5db199SXin Li
130*9c5db199SXin Li    # TODO: check if its already build. .version? hash?
131*9c5db199SXin Li    test_name = client_test.__class__.__name__
132*9c5db199SXin Li    cwd = os.getcwd()
133*9c5db199SXin Li    good_setup = False
134*9c5db199SXin Li    try:
135*9c5db199SXin Li        try:
136*9c5db199SXin Li            outputdir = os.path.join(client_test.job.resultdir, test_name)
137*9c5db199SXin Li            try:
138*9c5db199SXin Li                os.makedirs(outputdir)
139*9c5db199SXin Li                os.chdir(outputdir)
140*9c5db199SXin Li            except OSError:
141*9c5db199SXin Li                pass
142*9c5db199SXin Li            logging.info('setup %s.' % test_name)
143*9c5db199SXin Li            client_test.setup()
144*9c5db199SXin Li
145*9c5db199SXin Li            # Touch .version file under src to prevent further setup on client
146*9c5db199SXin Li            # host. See client/common_lib/utils.py update_version()
147*9c5db199SXin Li            if os.path.exists(client_test.srcdir):
148*9c5db199SXin Li                versionfile = os.path.join(client_test.srcdir, '.version')
149*9c5db199SXin Li                pickle.dump(client_test.version, open(versionfile, 'wb'))
150*9c5db199SXin Li            good_setup = True
151*9c5db199SXin Li        except Exception as err:
152*9c5db199SXin Li            logging.error(err)
153*9c5db199SXin Li            raise error.AutoservError('Failed to build client test %s on '
154*9c5db199SXin Li                                      'server.' % test_name)
155*9c5db199SXin Li    finally:
156*9c5db199SXin Li        # back to original working dir
157*9c5db199SXin Li        os.chdir(cwd)
158*9c5db199SXin Li    return good_setup
159*9c5db199SXin Li
160*9c5db199SXin Li
161*9c5db199SXin Lidef setup_tests(options):
162*9c5db199SXin Li    """
163*9c5db199SXin Li    Load and instantiate all client tests.
164*9c5db199SXin Li
165*9c5db199SXin Li    This function is inspired from runtest() on client/common_lib/test.py.
166*9c5db199SXin Li
167*9c5db199SXin Li    @param options: an object passed in from command line OptionParser.
168*9c5db199SXin Li                    See all options defined on client/bin/autotest.
169*9c5db199SXin Li    """
170*9c5db199SXin Li
171*9c5db199SXin Li    assert options.client_test_setup, 'Specify prebuild client tests on the ' \
172*9c5db199SXin Li                                      'command line.'
173*9c5db199SXin Li
174*9c5db199SXin Li    requested_tests = options.client_test_setup.split(',')
175*9c5db199SXin Li    candidates, broken_tests = load_all_client_tests(options)
176*9c5db199SXin Li
177*9c5db199SXin Li    failed_tests = []
178*9c5db199SXin Li    if 'all' in requested_tests:
179*9c5db199SXin Li        need_to_setup = candidates
180*9c5db199SXin Li        failed_tests += broken_tests
181*9c5db199SXin Li    else:
182*9c5db199SXin Li        need_to_setup = []
183*9c5db199SXin Li        for candidate in candidates:
184*9c5db199SXin Li            if candidate.__class__.__name__ in requested_tests:
185*9c5db199SXin Li                need_to_setup.append(candidate)
186*9c5db199SXin Li        for broken_test in broken_tests:
187*9c5db199SXin Li            if broken_test in requested_tests:
188*9c5db199SXin Li                failed_tests.append(broken_test)
189*9c5db199SXin Li
190*9c5db199SXin Li    if need_to_setup:
191*9c5db199SXin Li        cwd = os.getcwd()
192*9c5db199SXin Li        os.chdir(need_to_setup[0].job.clientdir)
193*9c5db199SXin Li        os.system('tools/make_clean')
194*9c5db199SXin Li        os.chdir(cwd)
195*9c5db199SXin Li    elif not failed_tests:
196*9c5db199SXin Li        logging.error('### No test setup candidates ###')
197*9c5db199SXin Li        raise error.AutoservError('No test setup candidates.')
198*9c5db199SXin Li
199*9c5db199SXin Li    for client_test in need_to_setup:
200*9c5db199SXin Li        good_setup = setup_test(client_test)
201*9c5db199SXin Li        if not good_setup:
202*9c5db199SXin Li            failed_tests.append(client_test.__class__.__name__)
203*9c5db199SXin Li
204*9c5db199SXin Li    logging.info('############################# SUMMARY '
205*9c5db199SXin Li                 '#############################')
206*9c5db199SXin Li
207*9c5db199SXin Li    # Print out tests that failed
208*9c5db199SXin Li    if failed_tests:
209*9c5db199SXin Li        logging.info('Finished setup -- The following tests failed')
210*9c5db199SXin Li        for failed_test in failed_tests:
211*9c5db199SXin Li            logging.info(failed_test)
212*9c5db199SXin Li    else:
213*9c5db199SXin Li        logging.info('Finished setup -- All tests built successfully')
214*9c5db199SXin Li    logging.info('######################### END SUMMARY '
215*9c5db199SXin Li                 '##############################')
216*9c5db199SXin Li    if failed_tests:
217*9c5db199SXin Li        raise error.AutoservError('Finished setup with errors.')
218