1c342db35SBrad Bishop## Copyright (C) 2016 Intel Corporation 2c342db35SBrad Bishop# 3c342db35SBrad Bishop# SPDX-License-Identifier: MIT 4c342db35SBrad Bishop# 5eb8dc403SDave Cobbley 6eb8dc403SDave Cobbleyimport os 7eb8dc403SDave Cobbleyimport sys 8eb8dc403SDave Cobbleyimport json 9eb8dc403SDave Cobbleyimport time 10eb8dc403SDave Cobbleyimport logging 11eb8dc403SDave Cobbleyimport collections 1215ae2509SBrad Bishopimport unittest 13eb8dc403SDave Cobbley 14eb8dc403SDave Cobbleyfrom oeqa.core.loader import OETestLoader 15eb8dc403SDave Cobbleyfrom oeqa.core.runner import OETestRunner 16eb8dc403SDave Cobbleyfrom oeqa.core.exception import OEQAMissingManifest, OEQATestNotFound 17eb8dc403SDave Cobbley 18eb8dc403SDave Cobbleyclass OETestContext(object): 19eb8dc403SDave Cobbley loaderClass = OETestLoader 20eb8dc403SDave Cobbley runnerClass = OETestRunner 21eb8dc403SDave Cobbley 22eb8dc403SDave Cobbley files_dir = os.path.abspath(os.path.join(os.path.dirname( 23eb8dc403SDave Cobbley os.path.abspath(__file__)), "../files")) 24eb8dc403SDave Cobbley 25eb8dc403SDave Cobbley def __init__(self, td=None, logger=None): 26eb8dc403SDave Cobbley if not type(td) is dict: 27eb8dc403SDave Cobbley raise TypeError("td isn't dictionary type") 28eb8dc403SDave Cobbley 29eb8dc403SDave Cobbley self.td = td 30eb8dc403SDave Cobbley self.logger = logger 31eb8dc403SDave Cobbley self._registry = {} 32eb8dc403SDave Cobbley self._registry['cases'] = collections.OrderedDict() 33eb8dc403SDave Cobbley 346ce62a20SAndrew Geissler self.results = unittest.TestResult() 356ce62a20SAndrew Geissler unittest.registerResult(self.results) 366ce62a20SAndrew Geissler 37eb8dc403SDave Cobbley def _read_modules_from_manifest(self, manifest): 38eb8dc403SDave Cobbley if not os.path.exists(manifest): 39eb8dc403SDave Cobbley raise OEQAMissingManifest("Manifest does not exist on %s" % manifest) 40eb8dc403SDave Cobbley 41eb8dc403SDave Cobbley modules = [] 42eb8dc403SDave Cobbley for line in open(manifest).readlines(): 43eb8dc403SDave Cobbley line = line.strip() 44eb8dc403SDave Cobbley if line and not line.startswith("#"): 45eb8dc403SDave Cobbley modules.append(line) 46eb8dc403SDave Cobbley 47eb8dc403SDave Cobbley return modules 48eb8dc403SDave Cobbley 49eb8dc403SDave Cobbley def skipTests(self, skips): 50eb8dc403SDave Cobbley if not skips: 51eb8dc403SDave Cobbley return 5215ae2509SBrad Bishop def skipfuncgen(skipmsg): 5315ae2509SBrad Bishop def func(): 5415ae2509SBrad Bishop raise unittest.SkipTest(skipmsg) 5515ae2509SBrad Bishop return func 56c8f47128SBrad Bishop class_ids = {} 57eb8dc403SDave Cobbley for test in self.suites: 58c8f47128SBrad Bishop if test.__class__ not in class_ids: 59c8f47128SBrad Bishop class_ids[test.__class__] = '.'.join(test.id().split('.')[:-1]) 60eb8dc403SDave Cobbley for skip in skips: 61c8f47128SBrad Bishop if (test.id()+'.').startswith(skip+'.'): 6215ae2509SBrad Bishop setattr(test, 'setUp', skipfuncgen('Skip by the command line argument "%s"' % skip)) 63c8f47128SBrad Bishop for tclass in class_ids: 64c8f47128SBrad Bishop cid = class_ids[tclass] 65c8f47128SBrad Bishop for skip in skips: 66c8f47128SBrad Bishop if (cid + '.').startswith(skip + '.'): 67c8f47128SBrad Bishop setattr(tclass, 'setUpHooker', skipfuncgen('Skip by the command line argument "%s"' % skip)) 68eb8dc403SDave Cobbley 69eb8dc403SDave Cobbley def loadTests(self, module_paths, modules=[], tests=[], 7079641f25SBrad Bishop modules_manifest="", modules_required=[], **kwargs): 71eb8dc403SDave Cobbley if modules_manifest: 72eb8dc403SDave Cobbley modules = self._read_modules_from_manifest(modules_manifest) 73eb8dc403SDave Cobbley 74eb8dc403SDave Cobbley self.loader = self.loaderClass(self, module_paths, modules, tests, 7579641f25SBrad Bishop modules_required, **kwargs) 76eb8dc403SDave Cobbley self.suites = self.loader.discover() 77eb8dc403SDave Cobbley 7882c905dcSAndrew Geissler def prepareSuite(self, suites, processes): 7982c905dcSAndrew Geissler return suites 8082c905dcSAndrew Geissler 811a4b7ee2SBrad Bishop def runTests(self, processes=None, skips=[]): 82eb8dc403SDave Cobbley self.runner = self.runnerClass(self, descriptions=False, verbosity=2) 83eb8dc403SDave Cobbley 84*fc113eadSAndrew Geissler # Dynamically skip those tests specified though arguments 85eb8dc403SDave Cobbley self.skipTests(skips) 86eb8dc403SDave Cobbley 87eb8dc403SDave Cobbley self._run_start_time = time.time() 886ce62a20SAndrew Geissler self._run_end_time = self._run_start_time 8982c905dcSAndrew Geissler if not processes: 901a4b7ee2SBrad Bishop self.runner.buffer = True 9182c905dcSAndrew Geissler result = self.runner.run(self.prepareSuite(self.suites, processes)) 92eb8dc403SDave Cobbley self._run_end_time = time.time() 93eb8dc403SDave Cobbley 94eb8dc403SDave Cobbley return result 95eb8dc403SDave Cobbley 96eb8dc403SDave Cobbley def listTests(self, display_type): 97eb8dc403SDave Cobbley self.runner = self.runnerClass(self, verbosity=2) 98eb8dc403SDave Cobbley return self.runner.list_tests(self.suites, display_type) 99eb8dc403SDave Cobbley 100eb8dc403SDave Cobbleyclass OETestContextExecutor(object): 101eb8dc403SDave Cobbley _context_class = OETestContext 102eb8dc403SDave Cobbley _script_executor = 'oe-test' 103eb8dc403SDave Cobbley 104eb8dc403SDave Cobbley name = 'core' 105eb8dc403SDave Cobbley help = 'core test component example' 106eb8dc403SDave Cobbley description = 'executes core test suite example' 10782c905dcSAndrew Geissler datetime = time.strftime("%Y%m%d%H%M%S") 108eb8dc403SDave Cobbley 109eb8dc403SDave Cobbley default_cases = [os.path.join(os.path.abspath(os.path.dirname(__file__)), 110eb8dc403SDave Cobbley 'cases/example')] 111eb8dc403SDave Cobbley default_test_data = os.path.join(default_cases[0], 'data.json') 112eb8dc403SDave Cobbley default_tests = None 11382c905dcSAndrew Geissler default_json_result_dir = None 114eb8dc403SDave Cobbley 115eb8dc403SDave Cobbley def register_commands(self, logger, subparsers): 116eb8dc403SDave Cobbley self.parser = subparsers.add_parser(self.name, help=self.help, 117eb8dc403SDave Cobbley description=self.description, group='components') 118eb8dc403SDave Cobbley 11982c905dcSAndrew Geissler self.default_output_log = '%s-results-%s.log' % (self.name, self.datetime) 120eb8dc403SDave Cobbley self.parser.add_argument('--output-log', action='store', 121eb8dc403SDave Cobbley default=self.default_output_log, 122eb8dc403SDave Cobbley help="results output log, default: %s" % self.default_output_log) 123eb8dc403SDave Cobbley 12482c905dcSAndrew Geissler self.parser.add_argument('--json-result-dir', action='store', 12582c905dcSAndrew Geissler default=self.default_json_result_dir, 12682c905dcSAndrew Geissler help="json result output dir, default: %s" % self.default_json_result_dir) 12782c905dcSAndrew Geissler 128eb8dc403SDave Cobbley group = self.parser.add_mutually_exclusive_group() 129eb8dc403SDave Cobbley group.add_argument('--run-tests', action='store', nargs='+', 130eb8dc403SDave Cobbley default=self.default_tests, 131eb8dc403SDave Cobbley help="tests to run in <module>[.<class>[.<name>]]") 132eb8dc403SDave Cobbley group.add_argument('--list-tests', action='store', 133eb8dc403SDave Cobbley choices=('module', 'class', 'name'), 134eb8dc403SDave Cobbley help="lists available tests") 135eb8dc403SDave Cobbley 136eb8dc403SDave Cobbley if self.default_test_data: 137eb8dc403SDave Cobbley self.parser.add_argument('--test-data-file', action='store', 138eb8dc403SDave Cobbley default=self.default_test_data, 139eb8dc403SDave Cobbley help="data file to load, default: %s" % self.default_test_data) 140eb8dc403SDave Cobbley else: 141eb8dc403SDave Cobbley self.parser.add_argument('--test-data-file', action='store', 142eb8dc403SDave Cobbley help="data file to load") 143eb8dc403SDave Cobbley 144eb8dc403SDave Cobbley if self.default_cases: 145eb8dc403SDave Cobbley self.parser.add_argument('CASES_PATHS', action='store', 146eb8dc403SDave Cobbley default=self.default_cases, nargs='*', 147eb8dc403SDave Cobbley help="paths to directories with test cases, default: %s"\ 148eb8dc403SDave Cobbley % self.default_cases) 149eb8dc403SDave Cobbley else: 150eb8dc403SDave Cobbley self.parser.add_argument('CASES_PATHS', action='store', 151eb8dc403SDave Cobbley nargs='+', help="paths to directories with test cases") 152eb8dc403SDave Cobbley 153eb8dc403SDave Cobbley self.parser.set_defaults(func=self.run) 154eb8dc403SDave Cobbley 155eb8dc403SDave Cobbley def _setup_logger(self, logger, args): 156eb8dc403SDave Cobbley formatter = logging.Formatter('%(asctime)s - ' + self.name + \ 157eb8dc403SDave Cobbley ' - %(levelname)s - %(message)s') 158eb8dc403SDave Cobbley sh = logger.handlers[0] 159eb8dc403SDave Cobbley sh.setFormatter(formatter) 160eb8dc403SDave Cobbley fh = logging.FileHandler(args.output_log) 161eb8dc403SDave Cobbley fh.setFormatter(formatter) 162eb8dc403SDave Cobbley logger.addHandler(fh) 1634ed12e16SAndrew Geissler if getattr(args, 'verbose', False): 1644ed12e16SAndrew Geissler logger.setLevel('DEBUG') 165eb8dc403SDave Cobbley 166eb8dc403SDave Cobbley return logger 167eb8dc403SDave Cobbley 168eb8dc403SDave Cobbley def _process_args(self, logger, args): 169eb8dc403SDave Cobbley self.tc_kwargs = {} 170eb8dc403SDave Cobbley self.tc_kwargs['init'] = {} 171eb8dc403SDave Cobbley self.tc_kwargs['load'] = {} 172eb8dc403SDave Cobbley self.tc_kwargs['list'] = {} 173eb8dc403SDave Cobbley self.tc_kwargs['run'] = {} 174eb8dc403SDave Cobbley 175eb8dc403SDave Cobbley self.tc_kwargs['init']['logger'] = self._setup_logger(logger, args) 176eb8dc403SDave Cobbley if args.test_data_file: 177eb8dc403SDave Cobbley self.tc_kwargs['init']['td'] = json.load( 178eb8dc403SDave Cobbley open(args.test_data_file, "r")) 179eb8dc403SDave Cobbley else: 180eb8dc403SDave Cobbley self.tc_kwargs['init']['td'] = {} 181eb8dc403SDave Cobbley 182eb8dc403SDave Cobbley if args.run_tests: 183eb8dc403SDave Cobbley self.tc_kwargs['load']['modules'] = args.run_tests 184eb8dc403SDave Cobbley self.tc_kwargs['load']['modules_required'] = args.run_tests 185eb8dc403SDave Cobbley else: 186eb8dc403SDave Cobbley self.tc_kwargs['load']['modules'] = [] 187eb8dc403SDave Cobbley 188eb8dc403SDave Cobbley self.tc_kwargs['run']['skips'] = [] 189eb8dc403SDave Cobbley 190eb8dc403SDave Cobbley self.module_paths = args.CASES_PATHS 191eb8dc403SDave Cobbley 19282c905dcSAndrew Geissler def _get_json_result_dir(self, args): 19382c905dcSAndrew Geissler return args.json_result_dir 19482c905dcSAndrew Geissler 19582c905dcSAndrew Geissler def _get_configuration(self): 19682c905dcSAndrew Geissler td = self.tc_kwargs['init']['td'] 19782c905dcSAndrew Geissler configuration = {'TEST_TYPE': self.name, 19882c905dcSAndrew Geissler 'MACHINE': td.get("MACHINE"), 19982c905dcSAndrew Geissler 'DISTRO': td.get("DISTRO"), 20082c905dcSAndrew Geissler 'IMAGE_BASENAME': td.get("IMAGE_BASENAME"), 20182c905dcSAndrew Geissler 'DATETIME': td.get("DATETIME")} 20282c905dcSAndrew Geissler return configuration 20382c905dcSAndrew Geissler 20482c905dcSAndrew Geissler def _get_result_id(self, configuration): 20582c905dcSAndrew Geissler return '%s_%s_%s_%s' % (configuration['TEST_TYPE'], configuration['IMAGE_BASENAME'], 20682c905dcSAndrew Geissler configuration['MACHINE'], self.datetime) 20782c905dcSAndrew Geissler 208eb8dc403SDave Cobbley def _pre_run(self): 209eb8dc403SDave Cobbley pass 210eb8dc403SDave Cobbley 211eb8dc403SDave Cobbley def run(self, logger, args): 212eb8dc403SDave Cobbley self._process_args(logger, args) 213eb8dc403SDave Cobbley 214eb8dc403SDave Cobbley self.tc = self._context_class(**self.tc_kwargs['init']) 215eb8dc403SDave Cobbley try: 216eb8dc403SDave Cobbley self.tc.loadTests(self.module_paths, **self.tc_kwargs['load']) 217eb8dc403SDave Cobbley except OEQATestNotFound as ex: 218eb8dc403SDave Cobbley logger.error(ex) 219eb8dc403SDave Cobbley sys.exit(1) 220eb8dc403SDave Cobbley 221eb8dc403SDave Cobbley if args.list_tests: 222eb8dc403SDave Cobbley rc = self.tc.listTests(args.list_tests, **self.tc_kwargs['list']) 223eb8dc403SDave Cobbley else: 224eb8dc403SDave Cobbley self._pre_run() 225eb8dc403SDave Cobbley rc = self.tc.runTests(**self.tc_kwargs['run']) 22682c905dcSAndrew Geissler 22782c905dcSAndrew Geissler json_result_dir = self._get_json_result_dir(args) 22882c905dcSAndrew Geissler if json_result_dir: 22982c905dcSAndrew Geissler configuration = self._get_configuration() 23082c905dcSAndrew Geissler rc.logDetails(json_result_dir, 23182c905dcSAndrew Geissler configuration, 23282c905dcSAndrew Geissler self._get_result_id(configuration)) 23382c905dcSAndrew Geissler else: 234eb8dc403SDave Cobbley rc.logDetails() 23582c905dcSAndrew Geissler 236eb8dc403SDave Cobbley rc.logSummary(self.name) 237eb8dc403SDave Cobbley 238eb8dc403SDave Cobbley output_link = os.path.join(os.path.dirname(args.output_log), 239eb8dc403SDave Cobbley "%s-results.log" % self.name) 240eb8dc403SDave Cobbley if os.path.exists(output_link): 241eb8dc403SDave Cobbley os.remove(output_link) 242eb8dc403SDave Cobbley os.symlink(args.output_log, output_link) 243eb8dc403SDave Cobbley 244eb8dc403SDave Cobbley return rc 245eb8dc403SDave Cobbley 246eb8dc403SDave Cobbley_executor_class = OETestContextExecutor 247