1# Copyright (C) 2017 Intel Corporation 2# Released under the MIT license (see COPYING.MIT) 3 4import os 5import time 6import glob 7import sys 8import imp 9import signal 10from shutil import copyfile 11from random import choice 12 13import oeqa 14 15from oeqa.core.context import OETestContext, OETestContextExecutor 16from oeqa.core.exception import OEQAPreRun, OEQATestNotFound 17 18from oeqa.utils.commands import runCmd, get_bb_vars, get_test_layer 19 20class OESelftestTestContext(OETestContext): 21 def __init__(self, td=None, logger=None, machines=None, config_paths=None): 22 super(OESelftestTestContext, self).__init__(td, logger) 23 24 self.machines = machines 25 self.custommachine = None 26 self.config_paths = config_paths 27 28 def runTests(self, machine=None, skips=[]): 29 if machine: 30 self.custommachine = machine 31 if machine == 'random': 32 self.custommachine = choice(self.machines) 33 self.logger.info('Run tests with custom MACHINE set to: %s' % \ 34 self.custommachine) 35 return super(OESelftestTestContext, self).runTests(skips) 36 37 def listTests(self, display_type, machine=None): 38 return super(OESelftestTestContext, self).listTests(display_type) 39 40class OESelftestTestContextExecutor(OETestContextExecutor): 41 _context_class = OESelftestTestContext 42 _script_executor = 'oe-selftest' 43 44 name = 'oe-selftest' 45 help = 'oe-selftest test component' 46 description = 'Executes selftest tests' 47 48 def register_commands(self, logger, parser): 49 group = parser.add_mutually_exclusive_group(required=True) 50 51 group.add_argument('-a', '--run-all-tests', default=False, 52 action="store_true", dest="run_all_tests", 53 help='Run all (unhidden) tests') 54 group.add_argument('-R', '--skip-tests', required=False, action='store', 55 nargs='+', dest="skips", default=None, 56 help='Run all (unhidden) tests except the ones specified. Format should be <module>[.<class>[.<test_method>]]') 57 group.add_argument('-r', '--run-tests', required=False, action='store', 58 nargs='+', dest="run_tests", default=None, 59 help='Select what tests to run (modules, classes or test methods). Format should be: <module>.<class>.<test_method>') 60 61 group.add_argument('-m', '--list-modules', required=False, 62 action="store_true", default=False, 63 help='List all available test modules.') 64 group.add_argument('--list-classes', required=False, 65 action="store_true", default=False, 66 help='List all available test classes.') 67 group.add_argument('-l', '--list-tests', required=False, 68 action="store_true", default=False, 69 help='List all available tests.') 70 71 parser.add_argument('--machine', required=False, choices=['random', 'all'], 72 help='Run tests on different machines (random/all).') 73 74 parser.set_defaults(func=self.run) 75 76 def _get_available_machines(self): 77 machines = [] 78 79 bbpath = self.tc_kwargs['init']['td']['BBPATH'].split(':') 80 81 for path in bbpath: 82 found_machines = glob.glob(os.path.join(path, 'conf', 'machine', '*.conf')) 83 if found_machines: 84 for i in found_machines: 85 # eg: '/home/<user>/poky/meta-intel/conf/machine/intel-core2-32.conf' 86 machines.append(os.path.splitext(os.path.basename(i))[0]) 87 88 return machines 89 90 def _get_cases_paths(self, bbpath): 91 cases_paths = [] 92 for layer in bbpath: 93 cases_dir = os.path.join(layer, 'lib', 'oeqa', 'selftest', 'cases') 94 if os.path.isdir(cases_dir): 95 cases_paths.append(cases_dir) 96 return cases_paths 97 98 def _process_args(self, logger, args): 99 args.output_log = '%s-results-%s.log' % (self.name, 100 time.strftime("%Y%m%d%H%M%S")) 101 args.test_data_file = None 102 args.CASES_PATHS = None 103 104 super(OESelftestTestContextExecutor, self)._process_args(logger, args) 105 106 if args.list_modules: 107 args.list_tests = 'module' 108 elif args.list_classes: 109 args.list_tests = 'class' 110 elif args.list_tests: 111 args.list_tests = 'name' 112 113 self.tc_kwargs['init']['td'] = get_bb_vars() 114 self.tc_kwargs['init']['machines'] = self._get_available_machines() 115 116 builddir = os.environ.get("BUILDDIR") 117 self.tc_kwargs['init']['config_paths'] = {} 118 self.tc_kwargs['init']['config_paths']['testlayer_path'] = \ 119 get_test_layer() 120 self.tc_kwargs['init']['config_paths']['builddir'] = builddir 121 self.tc_kwargs['init']['config_paths']['localconf'] = \ 122 os.path.join(builddir, "conf/local.conf") 123 self.tc_kwargs['init']['config_paths']['localconf_backup'] = \ 124 os.path.join(builddir, "conf/local.conf.orig") 125 self.tc_kwargs['init']['config_paths']['localconf_class_backup'] = \ 126 os.path.join(builddir, "conf/local.conf.bk") 127 self.tc_kwargs['init']['config_paths']['bblayers'] = \ 128 os.path.join(builddir, "conf/bblayers.conf") 129 self.tc_kwargs['init']['config_paths']['bblayers_backup'] = \ 130 os.path.join(builddir, "conf/bblayers.conf.orig") 131 self.tc_kwargs['init']['config_paths']['bblayers_class_backup'] = \ 132 os.path.join(builddir, "conf/bblayers.conf.bk") 133 134 copyfile(self.tc_kwargs['init']['config_paths']['localconf'], 135 self.tc_kwargs['init']['config_paths']['localconf_backup']) 136 copyfile(self.tc_kwargs['init']['config_paths']['bblayers'], 137 self.tc_kwargs['init']['config_paths']['bblayers_backup']) 138 139 self.tc_kwargs['run']['skips'] = args.skips 140 141 def _pre_run(self): 142 def _check_required_env_variables(vars): 143 for var in vars: 144 if not os.environ.get(var): 145 self.tc.logger.error("%s is not set. Did you forget to source your build environment setup script?" % var) 146 raise OEQAPreRun 147 148 def _check_presence_meta_selftest(): 149 builddir = os.environ.get("BUILDDIR") 150 if os.getcwd() != builddir: 151 self.tc.logger.info("Changing cwd to %s" % builddir) 152 os.chdir(builddir) 153 154 if not "meta-selftest" in self.tc.td["BBLAYERS"]: 155 self.tc.logger.warn("meta-selftest layer not found in BBLAYERS, adding it") 156 meta_selftestdir = os.path.join( 157 self.tc.td["BBLAYERS_FETCH_DIR"], 'meta-selftest') 158 if os.path.isdir(meta_selftestdir): 159 runCmd("bitbake-layers add-layer %s" %meta_selftestdir) 160 # reload data is needed because a meta-selftest layer was add 161 self.tc.td = get_bb_vars() 162 self.tc.config_paths['testlayer_path'] = get_test_layer() 163 else: 164 self.tc.logger.error("could not locate meta-selftest in:\n%s" % meta_selftestdir) 165 raise OEQAPreRun 166 167 def _add_layer_libs(): 168 bbpath = self.tc.td['BBPATH'].split(':') 169 layer_libdirs = [p for p in (os.path.join(l, 'lib') \ 170 for l in bbpath) if os.path.exists(p)] 171 if layer_libdirs: 172 self.tc.logger.info("Adding layer libraries:") 173 for l in layer_libdirs: 174 self.tc.logger.info("\t%s" % l) 175 176 sys.path.extend(layer_libdirs) 177 imp.reload(oeqa.selftest) 178 179 _check_required_env_variables(["BUILDDIR"]) 180 _check_presence_meta_selftest() 181 182 if "buildhistory.bbclass" in self.tc.td["BBINCLUDED"]: 183 self.tc.logger.error("You have buildhistory enabled already and this isn't recommended for selftest, please disable it first.") 184 raise OEQAPreRun 185 186 if "PRSERV_HOST" in self.tc.td: 187 self.tc.logger.error("Please unset PRSERV_HOST in order to run oe-selftest") 188 raise OEQAPreRun 189 190 if "SANITY_TESTED_DISTROS" in self.tc.td: 191 self.tc.logger.error("Please unset SANITY_TESTED_DISTROS in order to run oe-selftest") 192 raise OEQAPreRun 193 194 _add_layer_libs() 195 196 self.tc.logger.info("Running bitbake -p") 197 runCmd("bitbake -p") 198 199 def _internal_run(self, logger, args): 200 self.module_paths = self._get_cases_paths( 201 self.tc_kwargs['init']['td']['BBPATH'].split(':')) 202 203 self.tc = self._context_class(**self.tc_kwargs['init']) 204 try: 205 self.tc.loadTests(self.module_paths, **self.tc_kwargs['load']) 206 except OEQATestNotFound as ex: 207 logger.error(ex) 208 sys.exit(1) 209 210 if args.list_tests: 211 rc = self.tc.listTests(args.list_tests, **self.tc_kwargs['list']) 212 else: 213 self._pre_run() 214 rc = self.tc.runTests(**self.tc_kwargs['run']) 215 rc.logDetails() 216 rc.logSummary(self.name) 217 218 return rc 219 220 def _signal_clean_handler(self, signum, frame): 221 sys.exit(1) 222 223 def run(self, logger, args): 224 self._process_args(logger, args) 225 226 signal.signal(signal.SIGTERM, self._signal_clean_handler) 227 228 rc = None 229 try: 230 if args.machine: 231 logger.info('Custom machine mode enabled. MACHINE set to %s' % 232 args.machine) 233 234 if args.machine == 'all': 235 results = [] 236 for m in self.tc_kwargs['init']['machines']: 237 self.tc_kwargs['run']['machine'] = m 238 results.append(self._internal_run(logger, args)) 239 240 # XXX: the oe-selftest script only needs to know if one 241 # machine run fails 242 for r in results: 243 rc = r 244 if not r.wasSuccessful(): 245 break 246 247 else: 248 self.tc_kwargs['run']['machine'] = args.machine 249 return self._internal_run(logger, args) 250 251 else: 252 self.tc_kwargs['run']['machine'] = args.machine 253 rc = self._internal_run(logger, args) 254 finally: 255 config_paths = self.tc_kwargs['init']['config_paths'] 256 if os.path.exists(config_paths['localconf_backup']): 257 copyfile(config_paths['localconf_backup'], 258 config_paths['localconf']) 259 os.remove(config_paths['localconf_backup']) 260 261 if os.path.exists(config_paths['bblayers_backup']): 262 copyfile(config_paths['bblayers_backup'], 263 config_paths['bblayers']) 264 os.remove(config_paths['bblayers_backup']) 265 266 if os.path.exists(config_paths['localconf_class_backup']): 267 os.remove(config_paths['localconf_class_backup']) 268 if os.path.exists(config_paths['bblayers_class_backup']): 269 os.remove(config_paths['bblayers_class_backup']) 270 271 output_link = os.path.join(os.path.dirname(args.output_log), 272 "%s-results.log" % self.name) 273 if os.path.exists(output_link): 274 os.remove(output_link) 275 os.symlink(args.output_log, output_link) 276 277 return rc 278 279_executor_class = OESelftestTestContextExecutor 280