xref: /aosp_15_r20/external/openthread/tools/harness-automation/autothreadharness/runner.py (revision cfb92d1480a9e65faed56933e9c12405f45898b4)
1*cfb92d14SAndroid Build Coastguard Worker#!/usr/bin/env python
2*cfb92d14SAndroid Build Coastguard Worker#
3*cfb92d14SAndroid Build Coastguard Worker# Copyright (c) 2016, The OpenThread Authors.
4*cfb92d14SAndroid Build Coastguard Worker# All rights reserved.
5*cfb92d14SAndroid Build Coastguard Worker#
6*cfb92d14SAndroid Build Coastguard Worker# Redistribution and use in source and binary forms, with or without
7*cfb92d14SAndroid Build Coastguard Worker# modification, are permitted provided that the following conditions are met:
8*cfb92d14SAndroid Build Coastguard Worker# 1. Redistributions of source code must retain the above copyright
9*cfb92d14SAndroid Build Coastguard Worker#    notice, this list of conditions and the following disclaimer.
10*cfb92d14SAndroid Build Coastguard Worker# 2. Redistributions in binary form must reproduce the above copyright
11*cfb92d14SAndroid Build Coastguard Worker#    notice, this list of conditions and the following disclaimer in the
12*cfb92d14SAndroid Build Coastguard Worker#    documentation and/or other materials provided with the distribution.
13*cfb92d14SAndroid Build Coastguard Worker# 3. Neither the name of the copyright holder nor the
14*cfb92d14SAndroid Build Coastguard Worker#    names of its contributors may be used to endorse or promote products
15*cfb92d14SAndroid Build Coastguard Worker#    derived from this software without specific prior written permission.
16*cfb92d14SAndroid Build Coastguard Worker#
17*cfb92d14SAndroid Build Coastguard Worker# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18*cfb92d14SAndroid Build Coastguard Worker# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*cfb92d14SAndroid Build Coastguard Worker# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*cfb92d14SAndroid Build Coastguard Worker# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21*cfb92d14SAndroid Build Coastguard Worker# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22*cfb92d14SAndroid Build Coastguard Worker# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23*cfb92d14SAndroid Build Coastguard Worker# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*cfb92d14SAndroid Build Coastguard Worker# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25*cfb92d14SAndroid Build Coastguard Worker# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26*cfb92d14SAndroid Build Coastguard Worker# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27*cfb92d14SAndroid Build Coastguard Worker# POSSIBILITY OF SUCH DAMAGE.
28*cfb92d14SAndroid Build Coastguard Worker#
29*cfb92d14SAndroid Build Coastguard Worker
30*cfb92d14SAndroid Build Coastguard Workerimport ConfigParser
31*cfb92d14SAndroid Build Coastguard Workerimport argparse
32*cfb92d14SAndroid Build Coastguard Workerimport fnmatch
33*cfb92d14SAndroid Build Coastguard Workerimport logging
34*cfb92d14SAndroid Build Coastguard Workerimport json
35*cfb92d14SAndroid Build Coastguard Workerimport os
36*cfb92d14SAndroid Build Coastguard Workerimport sys
37*cfb92d14SAndroid Build Coastguard Workerimport time
38*cfb92d14SAndroid Build Coastguard Workerimport unittest
39*cfb92d14SAndroid Build Coastguard Workerfrom collections import OrderedDict
40*cfb92d14SAndroid Build Coastguard Worker
41*cfb92d14SAndroid Build Coastguard Workerfrom autothreadharness.harness_case import HarnessCase
42*cfb92d14SAndroid Build Coastguard Workerfrom autothreadharness.open_thread_controller import OpenThreadController
43*cfb92d14SAndroid Build Coastguard Workerfrom autothreadharness import settings
44*cfb92d14SAndroid Build Coastguard Worker
45*cfb92d14SAndroid Build Coastguard Workerlogging.basicConfig(level=logging.INFO)
46*cfb92d14SAndroid Build Coastguard Worker
47*cfb92d14SAndroid Build Coastguard Workerlogger = logging.getLogger()
48*cfb92d14SAndroid Build Coastguard Worker"""Logger: The global logger"""
49*cfb92d14SAndroid Build Coastguard Worker
50*cfb92d14SAndroid Build Coastguard Workerlogger.setLevel(logging.INFO)
51*cfb92d14SAndroid Build Coastguard Worker
52*cfb92d14SAndroid Build Coastguard WorkerRESUME_SCRIPT_PATH = "%appdata%\\Microsoft\\Windows\\Start Menu\\Programs\\" "Startup\\continue_harness.bat"
53*cfb92d14SAndroid Build Coastguard Worker
54*cfb92d14SAndroid Build Coastguard Worker
55*cfb92d14SAndroid Build Coastguard Workerclass SimpleTestResult(unittest.TestResult):
56*cfb92d14SAndroid Build Coastguard Worker
57*cfb92d14SAndroid Build Coastguard Worker    executions = 0
58*cfb92d14SAndroid Build Coastguard Worker
59*cfb92d14SAndroid Build Coastguard Worker    def __init__(self, path, auto_reboot_args=None, keep_explorer=False, add_all_devices=False):
60*cfb92d14SAndroid Build Coastguard Worker        """Record test results in json file
61*cfb92d14SAndroid Build Coastguard Worker
62*cfb92d14SAndroid Build Coastguard Worker        Args:
63*cfb92d14SAndroid Build Coastguard Worker            path (str): File path to record the results
64*cfb92d14SAndroid Build Coastguard Worker            auto_reboot (bool): Whether reboot when harness die
65*cfb92d14SAndroid Build Coastguard Worker        """
66*cfb92d14SAndroid Build Coastguard Worker        super(SimpleTestResult, self).__init__()
67*cfb92d14SAndroid Build Coastguard Worker        self.path = path
68*cfb92d14SAndroid Build Coastguard Worker        self.auto_reboot_args = auto_reboot_args
69*cfb92d14SAndroid Build Coastguard Worker        self.result = json.load(open(self.path, 'r'))
70*cfb92d14SAndroid Build Coastguard Worker        self.log_handler = None
71*cfb92d14SAndroid Build Coastguard Worker        self.started = None
72*cfb92d14SAndroid Build Coastguard Worker        self.keep_explorer = keep_explorer
73*cfb92d14SAndroid Build Coastguard Worker        self.add_all_devices = add_all_devices
74*cfb92d14SAndroid Build Coastguard Worker        SimpleTestResult.executions += 1
75*cfb92d14SAndroid Build Coastguard Worker        logger.info('Initial state is %s', json.dumps(self.result, indent=2))
76*cfb92d14SAndroid Build Coastguard Worker
77*cfb92d14SAndroid Build Coastguard Worker    def startTest(self, test):
78*cfb92d14SAndroid Build Coastguard Worker        logger.info(
79*cfb92d14SAndroid Build Coastguard Worker            '\n========================================\n%s\n========================================',
80*cfb92d14SAndroid Build Coastguard Worker            test.__class__.__name__,
81*cfb92d14SAndroid Build Coastguard Worker        )
82*cfb92d14SAndroid Build Coastguard Worker
83*cfb92d14SAndroid Build Coastguard Worker        test.add_all_devices = self.add_all_devices
84*cfb92d14SAndroid Build Coastguard Worker        # create start up script if auto reboot enabled
85*cfb92d14SAndroid Build Coastguard Worker        if self.auto_reboot_args:
86*cfb92d14SAndroid Build Coastguard Worker            test.auto_reboot = True
87*cfb92d14SAndroid Build Coastguard Worker            os.system('echo %s > "%s"' %
88*cfb92d14SAndroid Build Coastguard Worker                      (' '.join(self.auto_reboot_args + ['-c', test.__class__.__name__]), RESUME_SCRIPT_PATH))
89*cfb92d14SAndroid Build Coastguard Worker
90*cfb92d14SAndroid Build Coastguard Worker        # record start timestamp
91*cfb92d14SAndroid Build Coastguard Worker        self.started = time.strftime('%Y-%m-%dT%H:%M:%S')
92*cfb92d14SAndroid Build Coastguard Worker
93*cfb92d14SAndroid Build Coastguard Worker        os.system('mkdir %s' % test.result_dir)
94*cfb92d14SAndroid Build Coastguard Worker        self.log_handler = logging.FileHandler('%s\\auto-%s.log' % (test.result_dir, time.strftime('%Y%m%d%H%M%S')))
95*cfb92d14SAndroid Build Coastguard Worker        self.log_handler.setLevel(logging.DEBUG)
96*cfb92d14SAndroid Build Coastguard Worker        self.log_handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(message)s'))
97*cfb92d14SAndroid Build Coastguard Worker        logger.addHandler(self.log_handler)
98*cfb92d14SAndroid Build Coastguard Worker
99*cfb92d14SAndroid Build Coastguard Worker    def add_result(self, test, passed, error=None):
100*cfb92d14SAndroid Build Coastguard Worker        """Record test result into json file
101*cfb92d14SAndroid Build Coastguard Worker
102*cfb92d14SAndroid Build Coastguard Worker        Args:
103*cfb92d14SAndroid Build Coastguard Worker            test (TestCase): The test just run
104*cfb92d14SAndroid Build Coastguard Worker            passed (bool): Whether the case is passed
105*cfb92d14SAndroid Build Coastguard Worker        """
106*cfb92d14SAndroid Build Coastguard Worker        fails = self.result.get(test.__class__.__name__, {}).get('fails', 0)
107*cfb92d14SAndroid Build Coastguard Worker        if passed is False:
108*cfb92d14SAndroid Build Coastguard Worker            fails += 1
109*cfb92d14SAndroid Build Coastguard Worker        self.result[str(test.__class__.__name__)] = {
110*cfb92d14SAndroid Build Coastguard Worker            'started': self.started,
111*cfb92d14SAndroid Build Coastguard Worker            'stopped': time.strftime('%Y-%m-%dT%H:%M:%S'),
112*cfb92d14SAndroid Build Coastguard Worker            'passed': passed,
113*cfb92d14SAndroid Build Coastguard Worker            'fails': fails,
114*cfb92d14SAndroid Build Coastguard Worker            'error': error,
115*cfb92d14SAndroid Build Coastguard Worker            'executions': SimpleTestResult.executions,
116*cfb92d14SAndroid Build Coastguard Worker        }
117*cfb92d14SAndroid Build Coastguard Worker        if self.auto_reboot_args:
118*cfb92d14SAndroid Build Coastguard Worker            os.system('del "%s"' % RESUME_SCRIPT_PATH)
119*cfb92d14SAndroid Build Coastguard Worker
120*cfb92d14SAndroid Build Coastguard Worker        json.dump(OrderedDict(sorted(self.result.items(), key=lambda t: t[0])), open(self.path, 'w'), indent=2)
121*cfb92d14SAndroid Build Coastguard Worker
122*cfb92d14SAndroid Build Coastguard Worker        # save logs
123*cfb92d14SAndroid Build Coastguard Worker        logger.removeHandler(self.log_handler)
124*cfb92d14SAndroid Build Coastguard Worker        self.log_handler.close()
125*cfb92d14SAndroid Build Coastguard Worker        self.log_handler = None
126*cfb92d14SAndroid Build Coastguard Worker        time.sleep(2)
127*cfb92d14SAndroid Build Coastguard Worker
128*cfb92d14SAndroid Build Coastguard Worker        # close explorers
129*cfb92d14SAndroid Build Coastguard Worker        if not self.keep_explorer:
130*cfb92d14SAndroid Build Coastguard Worker            os.system('taskkill /f /im explorer.exe && start explorer.exe')
131*cfb92d14SAndroid Build Coastguard Worker
132*cfb92d14SAndroid Build Coastguard Worker    def addSuccess(self, test):
133*cfb92d14SAndroid Build Coastguard Worker        logger.info('case[%s] pass', test.__class__.__name__)
134*cfb92d14SAndroid Build Coastguard Worker        super(SimpleTestResult, self).addSuccess(test)
135*cfb92d14SAndroid Build Coastguard Worker        self.add_result(test, True)
136*cfb92d14SAndroid Build Coastguard Worker
137*cfb92d14SAndroid Build Coastguard Worker    def addFailure(self, test, err):
138*cfb92d14SAndroid Build Coastguard Worker        logger.warning('case[%s] fail', test.__class__.__name__)
139*cfb92d14SAndroid Build Coastguard Worker        super(SimpleTestResult, self).addFailure(test, err)
140*cfb92d14SAndroid Build Coastguard Worker        self.add_result(test, False)
141*cfb92d14SAndroid Build Coastguard Worker
142*cfb92d14SAndroid Build Coastguard Worker    def addError(self, test, err):
143*cfb92d14SAndroid Build Coastguard Worker        logger.error('case[%s] error', test.__class__.__name__, exc_info=err)
144*cfb92d14SAndroid Build Coastguard Worker
145*cfb92d14SAndroid Build Coastguard Worker        if err and err[0] is SystemExit:
146*cfb92d14SAndroid Build Coastguard Worker            if self.auto_reboot_args:
147*cfb92d14SAndroid Build Coastguard Worker                logger.warning('rebooting..')
148*cfb92d14SAndroid Build Coastguard Worker                os.system('shutdown /r /t 1')
149*cfb92d14SAndroid Build Coastguard Worker            else:
150*cfb92d14SAndroid Build Coastguard Worker                logger.warning('exiting..')
151*cfb92d14SAndroid Build Coastguard Worker            sys.exit(1)
152*cfb92d14SAndroid Build Coastguard Worker
153*cfb92d14SAndroid Build Coastguard Worker        super(SimpleTestResult, self).addError(test, err)
154*cfb92d14SAndroid Build Coastguard Worker        self.add_result(test, None, str(err[1]))
155*cfb92d14SAndroid Build Coastguard Worker
156*cfb92d14SAndroid Build Coastguard Worker
157*cfb92d14SAndroid Build Coastguard Workerdef list_devices(names=None, continue_from=None, **kwargs):
158*cfb92d14SAndroid Build Coastguard Worker    """List devices in settings file and print versions"""
159*cfb92d14SAndroid Build Coastguard Worker
160*cfb92d14SAndroid Build Coastguard Worker    if not names:
161*cfb92d14SAndroid Build Coastguard Worker        names = [device for device, _type in settings.GOLDEN_DEVICES if _type == 'OpenThread']
162*cfb92d14SAndroid Build Coastguard Worker
163*cfb92d14SAndroid Build Coastguard Worker    if continue_from:
164*cfb92d14SAndroid Build Coastguard Worker        continue_from = names.index(continue_from)
165*cfb92d14SAndroid Build Coastguard Worker    else:
166*cfb92d14SAndroid Build Coastguard Worker        continue_from = 0
167*cfb92d14SAndroid Build Coastguard Worker
168*cfb92d14SAndroid Build Coastguard Worker    for port in names[continue_from:]:
169*cfb92d14SAndroid Build Coastguard Worker        try:
170*cfb92d14SAndroid Build Coastguard Worker            with OpenThreadController(port) as otc:
171*cfb92d14SAndroid Build Coastguard Worker                print('%s: %s' % (port, otc.version))
172*cfb92d14SAndroid Build Coastguard Worker        except BaseException:
173*cfb92d14SAndroid Build Coastguard Worker            logger.exception('failed to get version of %s' % port)
174*cfb92d14SAndroid Build Coastguard Worker
175*cfb92d14SAndroid Build Coastguard Worker
176*cfb92d14SAndroid Build Coastguard Workerdef discover(
177*cfb92d14SAndroid Build Coastguard Worker    names=None,
178*cfb92d14SAndroid Build Coastguard Worker    pattern=['*.py'],
179*cfb92d14SAndroid Build Coastguard Worker    skip='efp',
180*cfb92d14SAndroid Build Coastguard Worker    dry_run=False,
181*cfb92d14SAndroid Build Coastguard Worker    denylist=None,
182*cfb92d14SAndroid Build Coastguard Worker    name_greps=None,
183*cfb92d14SAndroid Build Coastguard Worker    manual_reset=False,
184*cfb92d14SAndroid Build Coastguard Worker    delete_history=False,
185*cfb92d14SAndroid Build Coastguard Worker    max_devices=0,
186*cfb92d14SAndroid Build Coastguard Worker    continue_from=None,
187*cfb92d14SAndroid Build Coastguard Worker    result_file='./result.json',
188*cfb92d14SAndroid Build Coastguard Worker    auto_reboot=False,
189*cfb92d14SAndroid Build Coastguard Worker    keep_explorer=False,
190*cfb92d14SAndroid Build Coastguard Worker    add_all_devices=False,
191*cfb92d14SAndroid Build Coastguard Worker):
192*cfb92d14SAndroid Build Coastguard Worker    """Discover all test cases and skip those passed
193*cfb92d14SAndroid Build Coastguard Worker
194*cfb92d14SAndroid Build Coastguard Worker    Args:
195*cfb92d14SAndroid Build Coastguard Worker        pattern (str): Pattern to match case modules, refer python's unittest
196*cfb92d14SAndroid Build Coastguard Worker                       documentation for more details
197*cfb92d14SAndroid Build Coastguard Worker        skip (str): types cases to skip
198*cfb92d14SAndroid Build Coastguard Worker    """
199*cfb92d14SAndroid Build Coastguard Worker    if not os.path.exists(settings.OUTPUT_PATH):
200*cfb92d14SAndroid Build Coastguard Worker        os.mkdir(settings.OUTPUT_PATH)
201*cfb92d14SAndroid Build Coastguard Worker
202*cfb92d14SAndroid Build Coastguard Worker    if delete_history:
203*cfb92d14SAndroid Build Coastguard Worker        os.system('del history.json')
204*cfb92d14SAndroid Build Coastguard Worker
205*cfb92d14SAndroid Build Coastguard Worker    if denylist:
206*cfb92d14SAndroid Build Coastguard Worker        try:
207*cfb92d14SAndroid Build Coastguard Worker            excludes = [line.strip('\n') for line in open(denylist, 'r').readlines() if not line.startswith('#')]
208*cfb92d14SAndroid Build Coastguard Worker        except BaseException:
209*cfb92d14SAndroid Build Coastguard Worker            logger.exception('Failed to open test case denylist file')
210*cfb92d14SAndroid Build Coastguard Worker            raise
211*cfb92d14SAndroid Build Coastguard Worker    else:
212*cfb92d14SAndroid Build Coastguard Worker        excludes = []
213*cfb92d14SAndroid Build Coastguard Worker
214*cfb92d14SAndroid Build Coastguard Worker    log = None
215*cfb92d14SAndroid Build Coastguard Worker    if os.path.isfile(result_file):
216*cfb92d14SAndroid Build Coastguard Worker        try:
217*cfb92d14SAndroid Build Coastguard Worker            log = json.load(open(result_file, 'r'))
218*cfb92d14SAndroid Build Coastguard Worker        except BaseException:
219*cfb92d14SAndroid Build Coastguard Worker            logger.exception('Failed to open result file')
220*cfb92d14SAndroid Build Coastguard Worker
221*cfb92d14SAndroid Build Coastguard Worker    if not log:
222*cfb92d14SAndroid Build Coastguard Worker        log = {}
223*cfb92d14SAndroid Build Coastguard Worker        json.dump(log, open(result_file, 'w'), indent=2)
224*cfb92d14SAndroid Build Coastguard Worker
225*cfb92d14SAndroid Build Coastguard Worker    new_th = False
226*cfb92d14SAndroid Build Coastguard Worker    harness_info = ConfigParser.ConfigParser()
227*cfb92d14SAndroid Build Coastguard Worker    harness_info.read('%s\\info.ini' % settings.HARNESS_HOME)
228*cfb92d14SAndroid Build Coastguard Worker    if harness_info.has_option('Thread_Harness_Info', 'Version') and harness_info.has_option(
229*cfb92d14SAndroid Build Coastguard Worker            'Thread_Harness_Info', 'Mode'):
230*cfb92d14SAndroid Build Coastguard Worker        harness_version = harness_info.get('Thread_Harness_Info', 'Version').rsplit(' ', 1)[1]
231*cfb92d14SAndroid Build Coastguard Worker        harness_mode = harness_info.get('Thread_Harness_Info', 'Mode')
232*cfb92d14SAndroid Build Coastguard Worker
233*cfb92d14SAndroid Build Coastguard Worker        if harness_mode == 'External' and harness_version > '1.4.0':
234*cfb92d14SAndroid Build Coastguard Worker            new_th = True
235*cfb92d14SAndroid Build Coastguard Worker
236*cfb92d14SAndroid Build Coastguard Worker        if harness_mode == 'Internal' and harness_version > '49.4':
237*cfb92d14SAndroid Build Coastguard Worker            new_th = True
238*cfb92d14SAndroid Build Coastguard Worker
239*cfb92d14SAndroid Build Coastguard Worker    suite = unittest.TestSuite()
240*cfb92d14SAndroid Build Coastguard Worker    if new_th:
241*cfb92d14SAndroid Build Coastguard Worker        discovered = unittest.defaultTestLoader.discover('cases', pattern)
242*cfb92d14SAndroid Build Coastguard Worker    else:
243*cfb92d14SAndroid Build Coastguard Worker        discovered = unittest.defaultTestLoader.discover('cases_R140', pattern)
244*cfb92d14SAndroid Build Coastguard Worker
245*cfb92d14SAndroid Build Coastguard Worker    if names and continue_from:
246*cfb92d14SAndroid Build Coastguard Worker        names = names[names.index(continue_from):]
247*cfb92d14SAndroid Build Coastguard Worker
248*cfb92d14SAndroid Build Coastguard Worker    for s1 in discovered:
249*cfb92d14SAndroid Build Coastguard Worker        for s2 in s1:
250*cfb92d14SAndroid Build Coastguard Worker            for case in s2:
251*cfb92d14SAndroid Build Coastguard Worker                if case.__class__ is HarnessCase:
252*cfb92d14SAndroid Build Coastguard Worker                    continue
253*cfb92d14SAndroid Build Coastguard Worker                case_name = str(case.__class__.__name__)
254*cfb92d14SAndroid Build Coastguard Worker
255*cfb92d14SAndroid Build Coastguard Worker                # grep name
256*cfb92d14SAndroid Build Coastguard Worker                if name_greps and not any(fnmatch.fnmatch(case_name, name_grep) for name_grep in name_greps):
257*cfb92d14SAndroid Build Coastguard Worker                    logger.info('case[%s] skipped by name greps', case_name)
258*cfb92d14SAndroid Build Coastguard Worker                    continue
259*cfb92d14SAndroid Build Coastguard Worker
260*cfb92d14SAndroid Build Coastguard Worker                # allowlist
261*cfb92d14SAndroid Build Coastguard Worker                if len(names) and case_name not in names:
262*cfb92d14SAndroid Build Coastguard Worker                    logger.info('case[%s] skipped', case_name)
263*cfb92d14SAndroid Build Coastguard Worker                    continue
264*cfb92d14SAndroid Build Coastguard Worker
265*cfb92d14SAndroid Build Coastguard Worker                # skip cases
266*cfb92d14SAndroid Build Coastguard Worker                if case_name in log:
267*cfb92d14SAndroid Build Coastguard Worker                    if ((log[case_name]['passed'] and ('p' in skip)) or
268*cfb92d14SAndroid Build Coastguard Worker                        (log[case_name]['passed'] is False and ('f' in skip)) or (log[case_name]['passed'] is None and
269*cfb92d14SAndroid Build Coastguard Worker                                                                                  ('e' in skip))):
270*cfb92d14SAndroid Build Coastguard Worker                        logger.warning('case[%s] skipped for its status[%s]', case_name, log[case_name]['passed'])
271*cfb92d14SAndroid Build Coastguard Worker                        continue
272*cfb92d14SAndroid Build Coastguard Worker
273*cfb92d14SAndroid Build Coastguard Worker                # continue from
274*cfb92d14SAndroid Build Coastguard Worker                if continue_from:
275*cfb92d14SAndroid Build Coastguard Worker                    if continue_from != case_name:
276*cfb92d14SAndroid Build Coastguard Worker                        logger.warning('case[%s] skipped for continue from[%s]', case_name, continue_from)
277*cfb92d14SAndroid Build Coastguard Worker                        continue
278*cfb92d14SAndroid Build Coastguard Worker                    else:
279*cfb92d14SAndroid Build Coastguard Worker                        continue_from = None
280*cfb92d14SAndroid Build Coastguard Worker
281*cfb92d14SAndroid Build Coastguard Worker                # denylist
282*cfb92d14SAndroid Build Coastguard Worker                if case_name in excludes:
283*cfb92d14SAndroid Build Coastguard Worker                    logger.warning('case[%s] skipped for denylist', case_name)
284*cfb92d14SAndroid Build Coastguard Worker                    continue
285*cfb92d14SAndroid Build Coastguard Worker
286*cfb92d14SAndroid Build Coastguard Worker                # max devices
287*cfb92d14SAndroid Build Coastguard Worker                if max_devices and case.golden_devices_required > max_devices:
288*cfb92d14SAndroid Build Coastguard Worker                    logger.warning('case[%s] skipped for exceeding max golden devices allowed[%d]', case_name,
289*cfb92d14SAndroid Build Coastguard Worker                                   max_devices)
290*cfb92d14SAndroid Build Coastguard Worker                    continue
291*cfb92d14SAndroid Build Coastguard Worker
292*cfb92d14SAndroid Build Coastguard Worker                suite.addTest(case)
293*cfb92d14SAndroid Build Coastguard Worker                logger.info('case[%s] added', case_name)
294*cfb92d14SAndroid Build Coastguard Worker
295*cfb92d14SAndroid Build Coastguard Worker    if auto_reboot:
296*cfb92d14SAndroid Build Coastguard Worker        argv = []
297*cfb92d14SAndroid Build Coastguard Worker        argv.append('"%s"' % os.sep.join([os.getcwd(), 'start.bat']))
298*cfb92d14SAndroid Build Coastguard Worker        argv.extend(['-p', pattern])
299*cfb92d14SAndroid Build Coastguard Worker        argv.extend(['-k', skip])
300*cfb92d14SAndroid Build Coastguard Worker        argv.extend(['-o', result_file])
301*cfb92d14SAndroid Build Coastguard Worker        argv.append('-a')
302*cfb92d14SAndroid Build Coastguard Worker
303*cfb92d14SAndroid Build Coastguard Worker        if manual_reset:
304*cfb92d14SAndroid Build Coastguard Worker            argv.append('-m')
305*cfb92d14SAndroid Build Coastguard Worker
306*cfb92d14SAndroid Build Coastguard Worker        if delete_history:
307*cfb92d14SAndroid Build Coastguard Worker            argv.append('-d')
308*cfb92d14SAndroid Build Coastguard Worker
309*cfb92d14SAndroid Build Coastguard Worker        auto_reboot_args = argv + names
310*cfb92d14SAndroid Build Coastguard Worker    else:
311*cfb92d14SAndroid Build Coastguard Worker        auto_reboot_args = None
312*cfb92d14SAndroid Build Coastguard Worker        if os.path.isfile(RESUME_SCRIPT_PATH):
313*cfb92d14SAndroid Build Coastguard Worker            os.system('del "%s"' % RESUME_SCRIPT_PATH)
314*cfb92d14SAndroid Build Coastguard Worker
315*cfb92d14SAndroid Build Coastguard Worker    # manual reset
316*cfb92d14SAndroid Build Coastguard Worker    if manual_reset:
317*cfb92d14SAndroid Build Coastguard Worker        settings.PDU_CONTROLLER_TYPE = 'MANUAL_PDU_CONTROLLER'
318*cfb92d14SAndroid Build Coastguard Worker        settings.PDU_CONTROLLER_OPEN_PARAMS = {}
319*cfb92d14SAndroid Build Coastguard Worker        settings.PDU_CONTROLLER_REBOOT_PARAMS = {}
320*cfb92d14SAndroid Build Coastguard Worker
321*cfb92d14SAndroid Build Coastguard Worker    result = SimpleTestResult(result_file, auto_reboot_args, keep_explorer, add_all_devices)
322*cfb92d14SAndroid Build Coastguard Worker    for case in suite:
323*cfb92d14SAndroid Build Coastguard Worker        logger.info(case.__class__.__name__)
324*cfb92d14SAndroid Build Coastguard Worker
325*cfb92d14SAndroid Build Coastguard Worker    if dry_run:
326*cfb92d14SAndroid Build Coastguard Worker        return
327*cfb92d14SAndroid Build Coastguard Worker
328*cfb92d14SAndroid Build Coastguard Worker    suite.run(result)
329*cfb92d14SAndroid Build Coastguard Worker    return result
330*cfb92d14SAndroid Build Coastguard Worker
331*cfb92d14SAndroid Build Coastguard Worker
332*cfb92d14SAndroid Build Coastguard Workerdef main():
333*cfb92d14SAndroid Build Coastguard Worker    parser = argparse.ArgumentParser(description='Thread harness test case runner')
334*cfb92d14SAndroid Build Coastguard Worker    parser.add_argument('--auto-reboot',
335*cfb92d14SAndroid Build Coastguard Worker                        '-a',
336*cfb92d14SAndroid Build Coastguard Worker                        action='store_true',
337*cfb92d14SAndroid Build Coastguard Worker                        default=False,
338*cfb92d14SAndroid Build Coastguard Worker                        help='restart system when harness service die')
339*cfb92d14SAndroid Build Coastguard Worker    parser.add_argument('names',
340*cfb92d14SAndroid Build Coastguard Worker                        metavar='NAME',
341*cfb92d14SAndroid Build Coastguard Worker                        type=str,
342*cfb92d14SAndroid Build Coastguard Worker                        nargs='*',
343*cfb92d14SAndroid Build Coastguard Worker                        default=None,
344*cfb92d14SAndroid Build Coastguard Worker                        help='test case name, omit to test all')
345*cfb92d14SAndroid Build Coastguard Worker    parser.add_argument('--denylist',
346*cfb92d14SAndroid Build Coastguard Worker                        '-b',
347*cfb92d14SAndroid Build Coastguard Worker                        metavar='DENYLIST_FILE',
348*cfb92d14SAndroid Build Coastguard Worker                        type=str,
349*cfb92d14SAndroid Build Coastguard Worker                        help='file to list test cases to skip',
350*cfb92d14SAndroid Build Coastguard Worker                        default=None)
351*cfb92d14SAndroid Build Coastguard Worker    parser.add_argument('--continue-from', '-c', type=str, default=None, help='first case to test')
352*cfb92d14SAndroid Build Coastguard Worker    parser.add_argument('--delete-history', '-d', action='store_true', default=False, help='clear history on startup')
353*cfb92d14SAndroid Build Coastguard Worker    parser.add_argument('--keep-explorer',
354*cfb92d14SAndroid Build Coastguard Worker                        '-e',
355*cfb92d14SAndroid Build Coastguard Worker                        action='store_true',
356*cfb92d14SAndroid Build Coastguard Worker                        default=False,
357*cfb92d14SAndroid Build Coastguard Worker                        help='do not restart explorer.exe at the end')
358*cfb92d14SAndroid Build Coastguard Worker    parser.add_argument('--name-greps', '-g', action='append', default=None, help='grep case by names')
359*cfb92d14SAndroid Build Coastguard Worker    parser.add_argument('--list-file', '-i', type=str, default=None, help='file to list cases names to test')
360*cfb92d14SAndroid Build Coastguard Worker    parser.add_argument(
361*cfb92d14SAndroid Build Coastguard Worker        '--skip',
362*cfb92d14SAndroid Build Coastguard Worker        '-k',
363*cfb92d14SAndroid Build Coastguard Worker        metavar='SKIP',
364*cfb92d14SAndroid Build Coastguard Worker        type=str,
365*cfb92d14SAndroid Build Coastguard Worker        help='type of results to skip. e for error, f for fail, p for pass.',
366*cfb92d14SAndroid Build Coastguard Worker        default='',
367*cfb92d14SAndroid Build Coastguard Worker    )
368*cfb92d14SAndroid Build Coastguard Worker    parser.add_argument('--list-devices', '-l', action='store_true', default=False, help='list devices')
369*cfb92d14SAndroid Build Coastguard Worker    parser.add_argument('--manual-reset', '-m', action='store_true', default=False, help='reset devices manually')
370*cfb92d14SAndroid Build Coastguard Worker    parser.add_argument('--dry-run', '-n', action='store_true', default=False, help='just show what to run')
371*cfb92d14SAndroid Build Coastguard Worker    parser.add_argument(
372*cfb92d14SAndroid Build Coastguard Worker        '--result-file',
373*cfb92d14SAndroid Build Coastguard Worker        '-o',
374*cfb92d14SAndroid Build Coastguard Worker        type=str,
375*cfb92d14SAndroid Build Coastguard Worker        default=settings.OUTPUT_PATH + '\\result.json',
376*cfb92d14SAndroid Build Coastguard Worker        help='file to store and read current status',
377*cfb92d14SAndroid Build Coastguard Worker    )
378*cfb92d14SAndroid Build Coastguard Worker    parser.add_argument('--pattern',
379*cfb92d14SAndroid Build Coastguard Worker                        '-p',
380*cfb92d14SAndroid Build Coastguard Worker                        metavar='PATTERN',
381*cfb92d14SAndroid Build Coastguard Worker                        type=str,
382*cfb92d14SAndroid Build Coastguard Worker                        help='file name pattern, default to "*.py"',
383*cfb92d14SAndroid Build Coastguard Worker                        default='*.py')
384*cfb92d14SAndroid Build Coastguard Worker    parser.add_argument('--rerun-fails', '-r', type=int, default=0, help='number of times to rerun failed test cases')
385*cfb92d14SAndroid Build Coastguard Worker    parser.add_argument('--add-all-devices',
386*cfb92d14SAndroid Build Coastguard Worker                        '-t',
387*cfb92d14SAndroid Build Coastguard Worker                        action='store_true',
388*cfb92d14SAndroid Build Coastguard Worker                        default=False,
389*cfb92d14SAndroid Build Coastguard Worker                        help='add all devices to the test bed')
390*cfb92d14SAndroid Build Coastguard Worker    parser.add_argument('--max-devices', '-u', type=int, default=0, help='max golden devices allowed')
391*cfb92d14SAndroid Build Coastguard Worker
392*cfb92d14SAndroid Build Coastguard Worker    args = vars(parser.parse_args())
393*cfb92d14SAndroid Build Coastguard Worker
394*cfb92d14SAndroid Build Coastguard Worker    if args['list_file']:
395*cfb92d14SAndroid Build Coastguard Worker        try:
396*cfb92d14SAndroid Build Coastguard Worker            names = [line.strip('\n') for line in open(args['list_file'], 'r').readlines() if not line.startswith('#')]
397*cfb92d14SAndroid Build Coastguard Worker        except BaseException:
398*cfb92d14SAndroid Build Coastguard Worker            logger.exception('Failed to open test case list file')
399*cfb92d14SAndroid Build Coastguard Worker            raise
400*cfb92d14SAndroid Build Coastguard Worker        else:
401*cfb92d14SAndroid Build Coastguard Worker            args['names'] = args['names'] + names
402*cfb92d14SAndroid Build Coastguard Worker
403*cfb92d14SAndroid Build Coastguard Worker    args.pop('list_file')
404*cfb92d14SAndroid Build Coastguard Worker
405*cfb92d14SAndroid Build Coastguard Worker    if args.pop('list_devices', False):
406*cfb92d14SAndroid Build Coastguard Worker        list_devices(**args)
407*cfb92d14SAndroid Build Coastguard Worker        return
408*cfb92d14SAndroid Build Coastguard Worker
409*cfb92d14SAndroid Build Coastguard Worker    rerun_fails = args.pop('rerun_fails')
410*cfb92d14SAndroid Build Coastguard Worker    result = discover(**args)
411*cfb92d14SAndroid Build Coastguard Worker
412*cfb92d14SAndroid Build Coastguard Worker    if rerun_fails > 0:
413*cfb92d14SAndroid Build Coastguard Worker        for i in range(rerun_fails):
414*cfb92d14SAndroid Build Coastguard Worker            failed_names = {name for name in result.result if result.result[name]['passed'] is False}
415*cfb92d14SAndroid Build Coastguard Worker            if not failed_names:
416*cfb92d14SAndroid Build Coastguard Worker                break
417*cfb92d14SAndroid Build Coastguard Worker            logger.info('Rerunning failed test cases')
418*cfb92d14SAndroid Build Coastguard Worker            logger.info('Rerun #{}:'.format(i + 1))
419*cfb92d14SAndroid Build Coastguard Worker            result = discover(
420*cfb92d14SAndroid Build Coastguard Worker                names=failed_names,
421*cfb92d14SAndroid Build Coastguard Worker                pattern=args['pattern'],
422*cfb92d14SAndroid Build Coastguard Worker                skip='',
423*cfb92d14SAndroid Build Coastguard Worker                result_file=args['result_file'],
424*cfb92d14SAndroid Build Coastguard Worker                auto_reboot=args['auto_reboot'],
425*cfb92d14SAndroid Build Coastguard Worker                keep_explorer=args['keep_explorer'],
426*cfb92d14SAndroid Build Coastguard Worker                add_all_devices=args['add_all_devices'],
427*cfb92d14SAndroid Build Coastguard Worker            )
428*cfb92d14SAndroid Build Coastguard Worker
429*cfb92d14SAndroid Build Coastguard Worker
430*cfb92d14SAndroid Build Coastguard Workerif __name__ == '__main__':
431*cfb92d14SAndroid Build Coastguard Worker    main()
432