blob: 48ec5d419c7010714cac0db7bbdf858398a9d6d0 [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
Andrew Geissler82c905d2020-04-13 13:39:40 -050012import subprocess
Brad Bishopd7bf8c12018-02-25 22:55:05 -050013from random import choice
14
15import oeqa
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080016import oe
Andrew Geissler82c905d2020-04-13 13:39:40 -050017import bb.utils
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
Andrew Geissler82c905d2020-04-13 13:39:40 -050032 def setup_builddir(self, suffix, selftestdir, suite):
33 builddir = os.environ['BUILDDIR']
34 if not selftestdir:
35 selftestdir = get_test_layer()
36 newbuilddir = builddir + suffix
37 newselftestdir = newbuilddir + "/meta-selftest"
38
39 if os.path.exists(newbuilddir):
40 self.logger.error("Build directory %s already exists, aborting" % newbuilddir)
41 sys.exit(1)
42
43 bb.utils.mkdirhier(newbuilddir)
44 oe.path.copytree(builddir + "/conf", newbuilddir + "/conf")
45 oe.path.copytree(builddir + "/cache", newbuilddir + "/cache")
46 oe.path.copytree(selftestdir, newselftestdir)
47
48 for e in os.environ:
49 if builddir + "/" in os.environ[e] or os.environ[e].endswith(builddir):
50 os.environ[e] = os.environ[e].replace(builddir, newbuilddir)
51
52 subprocess.check_output("git init; git add *; git commit -a -m 'initial'", cwd=newselftestdir, shell=True)
53
54 # Tried to used bitbake-layers add/remove but it requires recipe parsing and hence is too slow
55 subprocess.check_output("sed %s/conf/bblayers.conf -i -e 's#%s#%s#g'" % (newbuilddir, selftestdir, newselftestdir), cwd=newbuilddir, shell=True)
56
57 os.chdir(newbuilddir)
58
59 for t in suite:
60 if not hasattr(t, "tc"):
61 continue
62 cp = t.tc.config_paths
63 for p in cp:
64 if selftestdir in cp[p] and newselftestdir not in cp[p]:
65 cp[p] = cp[p].replace(selftestdir, newselftestdir)
66 if builddir in cp[p] and newbuilddir not in cp[p]:
67 cp[p] = cp[p].replace(builddir, newbuilddir)
68
69 return (builddir, newbuilddir)
70
71 def prepareSuite(self, suites, processes):
72 if processes:
73 from oeqa.core.utils.concurrencytest import ConcurrentTestSuite
74
75 return ConcurrentTestSuite(suites, processes, self.setup_builddir)
76 else:
77 self.setup_builddir("-st", None, suites)
78 return suites
79
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080080 def runTests(self, processes=None, machine=None, skips=[]):
Brad Bishopd7bf8c12018-02-25 22:55:05 -050081 if machine:
82 self.custommachine = machine
83 if machine == 'random':
84 self.custommachine = choice(self.machines)
85 self.logger.info('Run tests with custom MACHINE set to: %s' % \
86 self.custommachine)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080087 return super(OESelftestTestContext, self).runTests(processes, skips)
Brad Bishopd7bf8c12018-02-25 22:55:05 -050088
89 def listTests(self, display_type, machine=None):
90 return super(OESelftestTestContext, self).listTests(display_type)
91
92class OESelftestTestContextExecutor(OETestContextExecutor):
93 _context_class = OESelftestTestContext
94 _script_executor = 'oe-selftest'
95
96 name = 'oe-selftest'
97 help = 'oe-selftest test component'
98 description = 'Executes selftest tests'
99
100 def register_commands(self, logger, parser):
101 group = parser.add_mutually_exclusive_group(required=True)
102
103 group.add_argument('-a', '--run-all-tests', default=False,
104 action="store_true", dest="run_all_tests",
105 help='Run all (unhidden) tests')
106 group.add_argument('-R', '--skip-tests', required=False, action='store',
107 nargs='+', dest="skips", default=None,
108 help='Run all (unhidden) tests except the ones specified. Format should be <module>[.<class>[.<test_method>]]')
109 group.add_argument('-r', '--run-tests', required=False, action='store',
110 nargs='+', dest="run_tests", default=None,
111 help='Select what tests to run (modules, classes or test methods). Format should be: <module>.<class>.<test_method>')
112
113 group.add_argument('-m', '--list-modules', required=False,
114 action="store_true", default=False,
115 help='List all available test modules.')
116 group.add_argument('--list-classes', required=False,
117 action="store_true", default=False,
118 help='List all available test classes.')
119 group.add_argument('-l', '--list-tests', required=False,
120 action="store_true", default=False,
121 help='List all available tests.')
122
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800123 parser.add_argument('-j', '--num-processes', dest='processes', action='store',
124 type=int, help="number of processes to execute in parallel with")
125
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500126 parser.add_argument('--machine', required=False, choices=['random', 'all'],
127 help='Run tests on different machines (random/all).')
Brad Bishop79641f22019-09-10 07:20:22 -0400128
Brad Bishopacc069e2019-09-13 06:48:36 -0400129 parser.add_argument('-t', '--select-tag', dest="select_tags",
130 action='append', default=None,
131 help='Filter all (unhidden) tests to any that match any of the specified tag(s).')
132 parser.add_argument('-T', '--exclude-tag', dest="exclude_tags",
133 action='append', default=None,
134 help='Exclude all (unhidden) tests that match any of the specified tag(s). (exclude applies before select)')
Brad Bishop79641f22019-09-10 07:20:22 -0400135
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500136 parser.set_defaults(func=self.run)
137
138 def _get_available_machines(self):
139 machines = []
140
141 bbpath = self.tc_kwargs['init']['td']['BBPATH'].split(':')
142
143 for path in bbpath:
144 found_machines = glob.glob(os.path.join(path, 'conf', 'machine', '*.conf'))
145 if found_machines:
146 for i in found_machines:
147 # eg: '/home/<user>/poky/meta-intel/conf/machine/intel-core2-32.conf'
148 machines.append(os.path.splitext(os.path.basename(i))[0])
149
150 return machines
151
152 def _get_cases_paths(self, bbpath):
153 cases_paths = []
154 for layer in bbpath:
155 cases_dir = os.path.join(layer, 'lib', 'oeqa', 'selftest', 'cases')
156 if os.path.isdir(cases_dir):
157 cases_paths.append(cases_dir)
158 return cases_paths
159
160 def _process_args(self, logger, args):
Brad Bishopf86d0552018-12-04 14:18:15 -0800161 args.test_start_time = time.strftime("%Y%m%d%H%M%S")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500162 args.test_data_file = None
163 args.CASES_PATHS = None
164
Brad Bishopf86d0552018-12-04 14:18:15 -0800165 bbvars = get_bb_vars()
166 logdir = os.environ.get("BUILDDIR")
167 if 'LOG_DIR' in bbvars:
168 logdir = bbvars['LOG_DIR']
Brad Bishop19323692019-04-05 15:28:33 -0400169 bb.utils.mkdirhier(logdir)
Brad Bishopf86d0552018-12-04 14:18:15 -0800170 args.output_log = logdir + '/%s-results-%s.log' % (self.name, args.test_start_time)
171
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500172 super(OESelftestTestContextExecutor, self)._process_args(logger, args)
173
174 if args.list_modules:
175 args.list_tests = 'module'
176 elif args.list_classes:
177 args.list_tests = 'class'
178 elif args.list_tests:
179 args.list_tests = 'name'
180
Brad Bishopf86d0552018-12-04 14:18:15 -0800181 self.tc_kwargs['init']['td'] = bbvars
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500182 self.tc_kwargs['init']['machines'] = self._get_available_machines()
183
184 builddir = os.environ.get("BUILDDIR")
185 self.tc_kwargs['init']['config_paths'] = {}
Andrew Geissler82c905d2020-04-13 13:39:40 -0500186 self.tc_kwargs['init']['config_paths']['testlayer_path'] = get_test_layer()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500187 self.tc_kwargs['init']['config_paths']['builddir'] = builddir
Andrew Geissler82c905d2020-04-13 13:39:40 -0500188 self.tc_kwargs['init']['config_paths']['localconf'] = os.path.join(builddir, "conf/local.conf")
189 self.tc_kwargs['init']['config_paths']['bblayers'] = os.path.join(builddir, "conf/bblayers.conf")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500190
Brad Bishop79641f22019-09-10 07:20:22 -0400191 def tag_filter(tags):
192 if args.exclude_tags:
193 if any(tag in args.exclude_tags for tag in tags):
194 return True
195 if args.select_tags:
196 if not tags or not any(tag in args.select_tags for tag in tags):
197 return True
198 return False
199
200 if args.select_tags or args.exclude_tags:
201 self.tc_kwargs['load']['tags_filter'] = tag_filter
202
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500203 self.tc_kwargs['run']['skips'] = args.skips
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800204 self.tc_kwargs['run']['processes'] = args.processes
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500205
206 def _pre_run(self):
207 def _check_required_env_variables(vars):
208 for var in vars:
209 if not os.environ.get(var):
210 self.tc.logger.error("%s is not set. Did you forget to source your build environment setup script?" % var)
211 raise OEQAPreRun
212
213 def _check_presence_meta_selftest():
214 builddir = os.environ.get("BUILDDIR")
215 if os.getcwd() != builddir:
216 self.tc.logger.info("Changing cwd to %s" % builddir)
217 os.chdir(builddir)
218
219 if not "meta-selftest" in self.tc.td["BBLAYERS"]:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800220 self.tc.logger.warning("meta-selftest layer not found in BBLAYERS, adding it")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500221 meta_selftestdir = os.path.join(
222 self.tc.td["BBLAYERS_FETCH_DIR"], 'meta-selftest')
223 if os.path.isdir(meta_selftestdir):
224 runCmd("bitbake-layers add-layer %s" %meta_selftestdir)
225 # reload data is needed because a meta-selftest layer was add
226 self.tc.td = get_bb_vars()
227 self.tc.config_paths['testlayer_path'] = get_test_layer()
228 else:
229 self.tc.logger.error("could not locate meta-selftest in:\n%s" % meta_selftestdir)
230 raise OEQAPreRun
231
232 def _add_layer_libs():
233 bbpath = self.tc.td['BBPATH'].split(':')
234 layer_libdirs = [p for p in (os.path.join(l, 'lib') \
235 for l in bbpath) if os.path.exists(p)]
236 if layer_libdirs:
237 self.tc.logger.info("Adding layer libraries:")
238 for l in layer_libdirs:
239 self.tc.logger.info("\t%s" % l)
240
241 sys.path.extend(layer_libdirs)
Brad Bishopf86d0552018-12-04 14:18:15 -0800242 importlib.reload(oeqa.selftest)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500243
244 _check_required_env_variables(["BUILDDIR"])
245 _check_presence_meta_selftest()
246
247 if "buildhistory.bbclass" in self.tc.td["BBINCLUDED"]:
248 self.tc.logger.error("You have buildhistory enabled already and this isn't recommended for selftest, please disable it first.")
249 raise OEQAPreRun
250
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800251 if "rm_work.bbclass" in self.tc.td["BBINCLUDED"]:
252 self.tc.logger.error("You have rm_work enabled which isn't recommended while running oe-selftest. Please disable it before continuing.")
253 raise OEQAPreRun
254
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500255 if "PRSERV_HOST" in self.tc.td:
256 self.tc.logger.error("Please unset PRSERV_HOST in order to run oe-selftest")
257 raise OEQAPreRun
258
259 if "SANITY_TESTED_DISTROS" in self.tc.td:
260 self.tc.logger.error("Please unset SANITY_TESTED_DISTROS in order to run oe-selftest")
261 raise OEQAPreRun
262
263 _add_layer_libs()
264
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800265 self.tc.logger.info("Running bitbake -e to test the configuration is valid/parsable")
266 runCmd("bitbake -e")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500267
Brad Bishopf86d0552018-12-04 14:18:15 -0800268 def get_json_result_dir(self, args):
269 json_result_dir = os.path.join(self.tc.td["LOG_DIR"], 'oeqa')
270 if "OEQA_JSON_RESULT_DIR" in self.tc.td:
271 json_result_dir = self.tc.td["OEQA_JSON_RESULT_DIR"]
272
273 return json_result_dir
274
275 def get_configuration(self, args):
276 import platform
277 from oeqa.utils.metadata import metadata_from_bb
278 metadata = metadata_from_bb()
279 configuration = {'TEST_TYPE': 'oeselftest',
280 'STARTTIME': args.test_start_time,
281 'MACHINE': self.tc.td["MACHINE"],
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800282 'HOST_DISTRO': oe.lsb.distro_identifier().replace(' ', '-'),
Brad Bishopf86d0552018-12-04 14:18:15 -0800283 'HOST_NAME': metadata['hostname'],
284 'LAYERS': metadata['layers']}
285 return configuration
286
287 def get_result_id(self, configuration):
288 return '%s_%s_%s_%s' % (configuration['TEST_TYPE'], configuration['HOST_DISTRO'], configuration['MACHINE'], configuration['STARTTIME'])
289
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500290 def _internal_run(self, logger, args):
291 self.module_paths = self._get_cases_paths(
292 self.tc_kwargs['init']['td']['BBPATH'].split(':'))
293
294 self.tc = self._context_class(**self.tc_kwargs['init'])
295 try:
296 self.tc.loadTests(self.module_paths, **self.tc_kwargs['load'])
297 except OEQATestNotFound as ex:
298 logger.error(ex)
299 sys.exit(1)
300
301 if args.list_tests:
302 rc = self.tc.listTests(args.list_tests, **self.tc_kwargs['list'])
303 else:
304 self._pre_run()
305 rc = self.tc.runTests(**self.tc_kwargs['run'])
Brad Bishopf86d0552018-12-04 14:18:15 -0800306 configuration = self.get_configuration(args)
307 rc.logDetails(self.get_json_result_dir(args),
308 configuration,
309 self.get_result_id(configuration))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500310 rc.logSummary(self.name)
311
312 return rc
313
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500314 def run(self, logger, args):
315 self._process_args(logger, args)
316
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500317 rc = None
318 try:
319 if args.machine:
320 logger.info('Custom machine mode enabled. MACHINE set to %s' %
321 args.machine)
322
323 if args.machine == 'all':
324 results = []
325 for m in self.tc_kwargs['init']['machines']:
326 self.tc_kwargs['run']['machine'] = m
327 results.append(self._internal_run(logger, args))
328
329 # XXX: the oe-selftest script only needs to know if one
330 # machine run fails
331 for r in results:
332 rc = r
333 if not r.wasSuccessful():
334 break
335
336 else:
337 self.tc_kwargs['run']['machine'] = args.machine
338 return self._internal_run(logger, args)
339
340 else:
341 self.tc_kwargs['run']['machine'] = args.machine
342 rc = self._internal_run(logger, args)
343 finally:
344 config_paths = self.tc_kwargs['init']['config_paths']
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500345
346 output_link = os.path.join(os.path.dirname(args.output_log),
347 "%s-results.log" % self.name)
Brad Bishopf86d0552018-12-04 14:18:15 -0800348 if os.path.lexists(output_link):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500349 os.remove(output_link)
350 os.symlink(args.output_log, output_link)
351
352 return rc
353
354_executor_class = OESelftestTestContextExecutor