blob: c4eb5d614eba8281b29d68eeb520b92a2c0f58ea [file] [log] [blame]
Brad Bishopc342db32019-05-15 21:57:59 -04001#
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002# Copyright (C) 2017 Intel Corporation
Brad Bishopc342db32019-05-15 21:57:59 -04003#
4# SPDX-License-Identifier: MIT
5#
Brad Bishopd7bf8c12018-02-25 22:55:05 -05006
7import os
8import time
9import glob
10import sys
Brad Bishopf86d0552018-12-04 14:18:15 -080011import importlib
Brad Bishopd7bf8c12018-02-25 22:55:05 -050012import signal
13from shutil import copyfile
14from random import choice
15
16import oeqa
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080017import oe
Brad Bishopd7bf8c12018-02-25 22:55:05 -050018
19from oeqa.core.context import OETestContext, OETestContextExecutor
20from oeqa.core.exception import OEQAPreRun, OEQATestNotFound
21
22from oeqa.utils.commands import runCmd, get_bb_vars, get_test_layer
23
24class OESelftestTestContext(OETestContext):
25 def __init__(self, td=None, logger=None, machines=None, config_paths=None):
26 super(OESelftestTestContext, self).__init__(td, logger)
27
28 self.machines = machines
29 self.custommachine = None
30 self.config_paths = config_paths
31
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080032 def runTests(self, processes=None, machine=None, skips=[]):
Brad Bishopd7bf8c12018-02-25 22:55:05 -050033 if machine:
34 self.custommachine = machine
35 if machine == 'random':
36 self.custommachine = choice(self.machines)
37 self.logger.info('Run tests with custom MACHINE set to: %s' % \
38 self.custommachine)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080039 return super(OESelftestTestContext, self).runTests(processes, skips)
Brad Bishopd7bf8c12018-02-25 22:55:05 -050040
41 def listTests(self, display_type, machine=None):
42 return super(OESelftestTestContext, self).listTests(display_type)
43
44class OESelftestTestContextExecutor(OETestContextExecutor):
45 _context_class = OESelftestTestContext
46 _script_executor = 'oe-selftest'
47
48 name = 'oe-selftest'
49 help = 'oe-selftest test component'
50 description = 'Executes selftest tests'
51
52 def register_commands(self, logger, parser):
53 group = parser.add_mutually_exclusive_group(required=True)
54
55 group.add_argument('-a', '--run-all-tests', default=False,
56 action="store_true", dest="run_all_tests",
57 help='Run all (unhidden) tests')
58 group.add_argument('-R', '--skip-tests', required=False, action='store',
59 nargs='+', dest="skips", default=None,
60 help='Run all (unhidden) tests except the ones specified. Format should be <module>[.<class>[.<test_method>]]')
61 group.add_argument('-r', '--run-tests', required=False, action='store',
62 nargs='+', dest="run_tests", default=None,
63 help='Select what tests to run (modules, classes or test methods). Format should be: <module>.<class>.<test_method>')
64
65 group.add_argument('-m', '--list-modules', required=False,
66 action="store_true", default=False,
67 help='List all available test modules.')
68 group.add_argument('--list-classes', required=False,
69 action="store_true", default=False,
70 help='List all available test classes.')
71 group.add_argument('-l', '--list-tests', required=False,
72 action="store_true", default=False,
73 help='List all available tests.')
74
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080075 parser.add_argument('-j', '--num-processes', dest='processes', action='store',
76 type=int, help="number of processes to execute in parallel with")
77
Brad Bishopd7bf8c12018-02-25 22:55:05 -050078 parser.add_argument('--machine', required=False, choices=['random', 'all'],
79 help='Run tests on different machines (random/all).')
Brad Bishop79641f22019-09-10 07:20:22 -040080
Brad Bishopacc069e2019-09-13 06:48:36 -040081 parser.add_argument('-t', '--select-tag', dest="select_tags",
82 action='append', default=None,
83 help='Filter all (unhidden) tests to any that match any of the specified tag(s).')
84 parser.add_argument('-T', '--exclude-tag', dest="exclude_tags",
85 action='append', default=None,
86 help='Exclude all (unhidden) tests that match any of the specified tag(s). (exclude applies before select)')
Brad Bishop79641f22019-09-10 07:20:22 -040087
Brad Bishopd7bf8c12018-02-25 22:55:05 -050088 parser.set_defaults(func=self.run)
89
90 def _get_available_machines(self):
91 machines = []
92
93 bbpath = self.tc_kwargs['init']['td']['BBPATH'].split(':')
94
95 for path in bbpath:
96 found_machines = glob.glob(os.path.join(path, 'conf', 'machine', '*.conf'))
97 if found_machines:
98 for i in found_machines:
99 # eg: '/home/<user>/poky/meta-intel/conf/machine/intel-core2-32.conf'
100 machines.append(os.path.splitext(os.path.basename(i))[0])
101
102 return machines
103
104 def _get_cases_paths(self, bbpath):
105 cases_paths = []
106 for layer in bbpath:
107 cases_dir = os.path.join(layer, 'lib', 'oeqa', 'selftest', 'cases')
108 if os.path.isdir(cases_dir):
109 cases_paths.append(cases_dir)
110 return cases_paths
111
112 def _process_args(self, logger, args):
Brad Bishopf86d0552018-12-04 14:18:15 -0800113 args.test_start_time = time.strftime("%Y%m%d%H%M%S")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500114 args.test_data_file = None
115 args.CASES_PATHS = None
116
Brad Bishopf86d0552018-12-04 14:18:15 -0800117 bbvars = get_bb_vars()
118 logdir = os.environ.get("BUILDDIR")
119 if 'LOG_DIR' in bbvars:
120 logdir = bbvars['LOG_DIR']
Brad Bishop19323692019-04-05 15:28:33 -0400121 bb.utils.mkdirhier(logdir)
Brad Bishopf86d0552018-12-04 14:18:15 -0800122 args.output_log = logdir + '/%s-results-%s.log' % (self.name, args.test_start_time)
123
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500124 super(OESelftestTestContextExecutor, self)._process_args(logger, args)
125
126 if args.list_modules:
127 args.list_tests = 'module'
128 elif args.list_classes:
129 args.list_tests = 'class'
130 elif args.list_tests:
131 args.list_tests = 'name'
132
Brad Bishopf86d0552018-12-04 14:18:15 -0800133 self.tc_kwargs['init']['td'] = bbvars
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500134 self.tc_kwargs['init']['machines'] = self._get_available_machines()
135
136 builddir = os.environ.get("BUILDDIR")
137 self.tc_kwargs['init']['config_paths'] = {}
138 self.tc_kwargs['init']['config_paths']['testlayer_path'] = \
139 get_test_layer()
140 self.tc_kwargs['init']['config_paths']['builddir'] = builddir
141 self.tc_kwargs['init']['config_paths']['localconf'] = \
142 os.path.join(builddir, "conf/local.conf")
143 self.tc_kwargs['init']['config_paths']['localconf_backup'] = \
144 os.path.join(builddir, "conf/local.conf.orig")
145 self.tc_kwargs['init']['config_paths']['localconf_class_backup'] = \
146 os.path.join(builddir, "conf/local.conf.bk")
147 self.tc_kwargs['init']['config_paths']['bblayers'] = \
148 os.path.join(builddir, "conf/bblayers.conf")
149 self.tc_kwargs['init']['config_paths']['bblayers_backup'] = \
150 os.path.join(builddir, "conf/bblayers.conf.orig")
151 self.tc_kwargs['init']['config_paths']['bblayers_class_backup'] = \
152 os.path.join(builddir, "conf/bblayers.conf.bk")
153
154 copyfile(self.tc_kwargs['init']['config_paths']['localconf'],
155 self.tc_kwargs['init']['config_paths']['localconf_backup'])
156 copyfile(self.tc_kwargs['init']['config_paths']['bblayers'],
157 self.tc_kwargs['init']['config_paths']['bblayers_backup'])
158
Brad Bishop79641f22019-09-10 07:20:22 -0400159 def tag_filter(tags):
160 if args.exclude_tags:
161 if any(tag in args.exclude_tags for tag in tags):
162 return True
163 if args.select_tags:
164 if not tags or not any(tag in args.select_tags for tag in tags):
165 return True
166 return False
167
168 if args.select_tags or args.exclude_tags:
169 self.tc_kwargs['load']['tags_filter'] = tag_filter
170
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500171 self.tc_kwargs['run']['skips'] = args.skips
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800172 self.tc_kwargs['run']['processes'] = args.processes
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500173
174 def _pre_run(self):
175 def _check_required_env_variables(vars):
176 for var in vars:
177 if not os.environ.get(var):
178 self.tc.logger.error("%s is not set. Did you forget to source your build environment setup script?" % var)
179 raise OEQAPreRun
180
181 def _check_presence_meta_selftest():
182 builddir = os.environ.get("BUILDDIR")
183 if os.getcwd() != builddir:
184 self.tc.logger.info("Changing cwd to %s" % builddir)
185 os.chdir(builddir)
186
187 if not "meta-selftest" in self.tc.td["BBLAYERS"]:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800188 self.tc.logger.warning("meta-selftest layer not found in BBLAYERS, adding it")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500189 meta_selftestdir = os.path.join(
190 self.tc.td["BBLAYERS_FETCH_DIR"], 'meta-selftest')
191 if os.path.isdir(meta_selftestdir):
192 runCmd("bitbake-layers add-layer %s" %meta_selftestdir)
193 # reload data is needed because a meta-selftest layer was add
194 self.tc.td = get_bb_vars()
195 self.tc.config_paths['testlayer_path'] = get_test_layer()
196 else:
197 self.tc.logger.error("could not locate meta-selftest in:\n%s" % meta_selftestdir)
198 raise OEQAPreRun
199
200 def _add_layer_libs():
201 bbpath = self.tc.td['BBPATH'].split(':')
202 layer_libdirs = [p for p in (os.path.join(l, 'lib') \
203 for l in bbpath) if os.path.exists(p)]
204 if layer_libdirs:
205 self.tc.logger.info("Adding layer libraries:")
206 for l in layer_libdirs:
207 self.tc.logger.info("\t%s" % l)
208
209 sys.path.extend(layer_libdirs)
Brad Bishopf86d0552018-12-04 14:18:15 -0800210 importlib.reload(oeqa.selftest)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500211
212 _check_required_env_variables(["BUILDDIR"])
213 _check_presence_meta_selftest()
214
215 if "buildhistory.bbclass" in self.tc.td["BBINCLUDED"]:
216 self.tc.logger.error("You have buildhistory enabled already and this isn't recommended for selftest, please disable it first.")
217 raise OEQAPreRun
218
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800219 if "rm_work.bbclass" in self.tc.td["BBINCLUDED"]:
220 self.tc.logger.error("You have rm_work enabled which isn't recommended while running oe-selftest. Please disable it before continuing.")
221 raise OEQAPreRun
222
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500223 if "PRSERV_HOST" in self.tc.td:
224 self.tc.logger.error("Please unset PRSERV_HOST in order to run oe-selftest")
225 raise OEQAPreRun
226
227 if "SANITY_TESTED_DISTROS" in self.tc.td:
228 self.tc.logger.error("Please unset SANITY_TESTED_DISTROS in order to run oe-selftest")
229 raise OEQAPreRun
230
231 _add_layer_libs()
232
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800233 self.tc.logger.info("Running bitbake -e to test the configuration is valid/parsable")
234 runCmd("bitbake -e")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500235
Brad Bishopf86d0552018-12-04 14:18:15 -0800236 def get_json_result_dir(self, args):
237 json_result_dir = os.path.join(self.tc.td["LOG_DIR"], 'oeqa')
238 if "OEQA_JSON_RESULT_DIR" in self.tc.td:
239 json_result_dir = self.tc.td["OEQA_JSON_RESULT_DIR"]
240
241 return json_result_dir
242
243 def get_configuration(self, args):
244 import platform
245 from oeqa.utils.metadata import metadata_from_bb
246 metadata = metadata_from_bb()
247 configuration = {'TEST_TYPE': 'oeselftest',
248 'STARTTIME': args.test_start_time,
249 'MACHINE': self.tc.td["MACHINE"],
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800250 'HOST_DISTRO': oe.lsb.distro_identifier().replace(' ', '-'),
Brad Bishopf86d0552018-12-04 14:18:15 -0800251 'HOST_NAME': metadata['hostname'],
252 'LAYERS': metadata['layers']}
253 return configuration
254
255 def get_result_id(self, configuration):
256 return '%s_%s_%s_%s' % (configuration['TEST_TYPE'], configuration['HOST_DISTRO'], configuration['MACHINE'], configuration['STARTTIME'])
257
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500258 def _internal_run(self, logger, args):
259 self.module_paths = self._get_cases_paths(
260 self.tc_kwargs['init']['td']['BBPATH'].split(':'))
261
262 self.tc = self._context_class(**self.tc_kwargs['init'])
263 try:
264 self.tc.loadTests(self.module_paths, **self.tc_kwargs['load'])
265 except OEQATestNotFound as ex:
266 logger.error(ex)
267 sys.exit(1)
268
269 if args.list_tests:
270 rc = self.tc.listTests(args.list_tests, **self.tc_kwargs['list'])
271 else:
272 self._pre_run()
273 rc = self.tc.runTests(**self.tc_kwargs['run'])
Brad Bishopf86d0552018-12-04 14:18:15 -0800274 configuration = self.get_configuration(args)
275 rc.logDetails(self.get_json_result_dir(args),
276 configuration,
277 self.get_result_id(configuration))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500278 rc.logSummary(self.name)
279
280 return rc
281
282 def _signal_clean_handler(self, signum, frame):
283 sys.exit(1)
284
285 def run(self, logger, args):
286 self._process_args(logger, args)
287
288 signal.signal(signal.SIGTERM, self._signal_clean_handler)
289
290 rc = None
291 try:
292 if args.machine:
293 logger.info('Custom machine mode enabled. MACHINE set to %s' %
294 args.machine)
295
296 if args.machine == 'all':
297 results = []
298 for m in self.tc_kwargs['init']['machines']:
299 self.tc_kwargs['run']['machine'] = m
300 results.append(self._internal_run(logger, args))
301
302 # XXX: the oe-selftest script only needs to know if one
303 # machine run fails
304 for r in results:
305 rc = r
306 if not r.wasSuccessful():
307 break
308
309 else:
310 self.tc_kwargs['run']['machine'] = args.machine
311 return self._internal_run(logger, args)
312
313 else:
314 self.tc_kwargs['run']['machine'] = args.machine
315 rc = self._internal_run(logger, args)
316 finally:
317 config_paths = self.tc_kwargs['init']['config_paths']
318 if os.path.exists(config_paths['localconf_backup']):
319 copyfile(config_paths['localconf_backup'],
320 config_paths['localconf'])
321 os.remove(config_paths['localconf_backup'])
322
323 if os.path.exists(config_paths['bblayers_backup']):
324 copyfile(config_paths['bblayers_backup'],
325 config_paths['bblayers'])
326 os.remove(config_paths['bblayers_backup'])
327
328 if os.path.exists(config_paths['localconf_class_backup']):
329 os.remove(config_paths['localconf_class_backup'])
330 if os.path.exists(config_paths['bblayers_class_backup']):
331 os.remove(config_paths['bblayers_class_backup'])
332
333 output_link = os.path.join(os.path.dirname(args.output_log),
334 "%s-results.log" % self.name)
Brad Bishopf86d0552018-12-04 14:18:15 -0800335 if os.path.lexists(output_link):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500336 os.remove(output_link)
337 os.symlink(args.output_log, output_link)
338
339 return rc
340
341_executor_class = OESelftestTestContextExecutor