blob: c56e53dcdd34d3d2363b419957cddde23b48454b [file] [log] [blame]
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001# Copyright (C) 2017 Intel Corporation
2# Released under the MIT license (see COPYING.MIT)
3
4import os
5import time
6import glob
7import sys
Brad Bishopf86d0552018-12-04 14:18:15 -08008import importlib
Brad Bishopd7bf8c12018-02-25 22:55:05 -05009import signal
10from shutil import copyfile
11from random import choice
12
13import oeqa
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080014import oe
Brad Bishopd7bf8c12018-02-25 22:55:05 -050015
16from oeqa.core.context import OETestContext, OETestContextExecutor
17from oeqa.core.exception import OEQAPreRun, OEQATestNotFound
18
19from oeqa.utils.commands import runCmd, get_bb_vars, get_test_layer
20
21class OESelftestTestContext(OETestContext):
22 def __init__(self, td=None, logger=None, machines=None, config_paths=None):
23 super(OESelftestTestContext, self).__init__(td, logger)
24
25 self.machines = machines
26 self.custommachine = None
27 self.config_paths = config_paths
28
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080029 def runTests(self, processes=None, machine=None, skips=[]):
Brad Bishopd7bf8c12018-02-25 22:55:05 -050030 if machine:
31 self.custommachine = machine
32 if machine == 'random':
33 self.custommachine = choice(self.machines)
34 self.logger.info('Run tests with custom MACHINE set to: %s' % \
35 self.custommachine)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080036 return super(OESelftestTestContext, self).runTests(processes, skips)
Brad Bishopd7bf8c12018-02-25 22:55:05 -050037
38 def listTests(self, display_type, machine=None):
39 return super(OESelftestTestContext, self).listTests(display_type)
40
41class OESelftestTestContextExecutor(OETestContextExecutor):
42 _context_class = OESelftestTestContext
43 _script_executor = 'oe-selftest'
44
45 name = 'oe-selftest'
46 help = 'oe-selftest test component'
47 description = 'Executes selftest tests'
48
49 def register_commands(self, logger, parser):
50 group = parser.add_mutually_exclusive_group(required=True)
51
52 group.add_argument('-a', '--run-all-tests', default=False,
53 action="store_true", dest="run_all_tests",
54 help='Run all (unhidden) tests')
55 group.add_argument('-R', '--skip-tests', required=False, action='store',
56 nargs='+', dest="skips", default=None,
57 help='Run all (unhidden) tests except the ones specified. Format should be <module>[.<class>[.<test_method>]]')
58 group.add_argument('-r', '--run-tests', required=False, action='store',
59 nargs='+', dest="run_tests", default=None,
60 help='Select what tests to run (modules, classes or test methods). Format should be: <module>.<class>.<test_method>')
61
62 group.add_argument('-m', '--list-modules', required=False,
63 action="store_true", default=False,
64 help='List all available test modules.')
65 group.add_argument('--list-classes', required=False,
66 action="store_true", default=False,
67 help='List all available test classes.')
68 group.add_argument('-l', '--list-tests', required=False,
69 action="store_true", default=False,
70 help='List all available tests.')
71
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080072 parser.add_argument('-j', '--num-processes', dest='processes', action='store',
73 type=int, help="number of processes to execute in parallel with")
74
Brad Bishopd7bf8c12018-02-25 22:55:05 -050075 parser.add_argument('--machine', required=False, choices=['random', 'all'],
76 help='Run tests on different machines (random/all).')
77
78 parser.set_defaults(func=self.run)
79
80 def _get_available_machines(self):
81 machines = []
82
83 bbpath = self.tc_kwargs['init']['td']['BBPATH'].split(':')
84
85 for path in bbpath:
86 found_machines = glob.glob(os.path.join(path, 'conf', 'machine', '*.conf'))
87 if found_machines:
88 for i in found_machines:
89 # eg: '/home/<user>/poky/meta-intel/conf/machine/intel-core2-32.conf'
90 machines.append(os.path.splitext(os.path.basename(i))[0])
91
92 return machines
93
94 def _get_cases_paths(self, bbpath):
95 cases_paths = []
96 for layer in bbpath:
97 cases_dir = os.path.join(layer, 'lib', 'oeqa', 'selftest', 'cases')
98 if os.path.isdir(cases_dir):
99 cases_paths.append(cases_dir)
100 return cases_paths
101
102 def _process_args(self, logger, args):
Brad Bishopf86d0552018-12-04 14:18:15 -0800103 args.test_start_time = time.strftime("%Y%m%d%H%M%S")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500104 args.test_data_file = None
105 args.CASES_PATHS = None
106
Brad Bishopf86d0552018-12-04 14:18:15 -0800107 bbvars = get_bb_vars()
108 logdir = os.environ.get("BUILDDIR")
109 if 'LOG_DIR' in bbvars:
110 logdir = bbvars['LOG_DIR']
Brad Bishop19323692019-04-05 15:28:33 -0400111 bb.utils.mkdirhier(logdir)
Brad Bishopf86d0552018-12-04 14:18:15 -0800112 args.output_log = logdir + '/%s-results-%s.log' % (self.name, args.test_start_time)
113
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500114 super(OESelftestTestContextExecutor, self)._process_args(logger, args)
115
116 if args.list_modules:
117 args.list_tests = 'module'
118 elif args.list_classes:
119 args.list_tests = 'class'
120 elif args.list_tests:
121 args.list_tests = 'name'
122
Brad Bishopf86d0552018-12-04 14:18:15 -0800123 self.tc_kwargs['init']['td'] = bbvars
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500124 self.tc_kwargs['init']['machines'] = self._get_available_machines()
125
126 builddir = os.environ.get("BUILDDIR")
127 self.tc_kwargs['init']['config_paths'] = {}
128 self.tc_kwargs['init']['config_paths']['testlayer_path'] = \
129 get_test_layer()
130 self.tc_kwargs['init']['config_paths']['builddir'] = builddir
131 self.tc_kwargs['init']['config_paths']['localconf'] = \
132 os.path.join(builddir, "conf/local.conf")
133 self.tc_kwargs['init']['config_paths']['localconf_backup'] = \
134 os.path.join(builddir, "conf/local.conf.orig")
135 self.tc_kwargs['init']['config_paths']['localconf_class_backup'] = \
136 os.path.join(builddir, "conf/local.conf.bk")
137 self.tc_kwargs['init']['config_paths']['bblayers'] = \
138 os.path.join(builddir, "conf/bblayers.conf")
139 self.tc_kwargs['init']['config_paths']['bblayers_backup'] = \
140 os.path.join(builddir, "conf/bblayers.conf.orig")
141 self.tc_kwargs['init']['config_paths']['bblayers_class_backup'] = \
142 os.path.join(builddir, "conf/bblayers.conf.bk")
143
144 copyfile(self.tc_kwargs['init']['config_paths']['localconf'],
145 self.tc_kwargs['init']['config_paths']['localconf_backup'])
146 copyfile(self.tc_kwargs['init']['config_paths']['bblayers'],
147 self.tc_kwargs['init']['config_paths']['bblayers_backup'])
148
149 self.tc_kwargs['run']['skips'] = args.skips
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800150 self.tc_kwargs['run']['processes'] = args.processes
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500151
152 def _pre_run(self):
153 def _check_required_env_variables(vars):
154 for var in vars:
155 if not os.environ.get(var):
156 self.tc.logger.error("%s is not set. Did you forget to source your build environment setup script?" % var)
157 raise OEQAPreRun
158
159 def _check_presence_meta_selftest():
160 builddir = os.environ.get("BUILDDIR")
161 if os.getcwd() != builddir:
162 self.tc.logger.info("Changing cwd to %s" % builddir)
163 os.chdir(builddir)
164
165 if not "meta-selftest" in self.tc.td["BBLAYERS"]:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800166 self.tc.logger.warning("meta-selftest layer not found in BBLAYERS, adding it")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500167 meta_selftestdir = os.path.join(
168 self.tc.td["BBLAYERS_FETCH_DIR"], 'meta-selftest')
169 if os.path.isdir(meta_selftestdir):
170 runCmd("bitbake-layers add-layer %s" %meta_selftestdir)
171 # reload data is needed because a meta-selftest layer was add
172 self.tc.td = get_bb_vars()
173 self.tc.config_paths['testlayer_path'] = get_test_layer()
174 else:
175 self.tc.logger.error("could not locate meta-selftest in:\n%s" % meta_selftestdir)
176 raise OEQAPreRun
177
178 def _add_layer_libs():
179 bbpath = self.tc.td['BBPATH'].split(':')
180 layer_libdirs = [p for p in (os.path.join(l, 'lib') \
181 for l in bbpath) if os.path.exists(p)]
182 if layer_libdirs:
183 self.tc.logger.info("Adding layer libraries:")
184 for l in layer_libdirs:
185 self.tc.logger.info("\t%s" % l)
186
187 sys.path.extend(layer_libdirs)
Brad Bishopf86d0552018-12-04 14:18:15 -0800188 importlib.reload(oeqa.selftest)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500189
190 _check_required_env_variables(["BUILDDIR"])
191 _check_presence_meta_selftest()
192
193 if "buildhistory.bbclass" in self.tc.td["BBINCLUDED"]:
194 self.tc.logger.error("You have buildhistory enabled already and this isn't recommended for selftest, please disable it first.")
195 raise OEQAPreRun
196
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800197 if "rm_work.bbclass" in self.tc.td["BBINCLUDED"]:
198 self.tc.logger.error("You have rm_work enabled which isn't recommended while running oe-selftest. Please disable it before continuing.")
199 raise OEQAPreRun
200
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500201 if "PRSERV_HOST" in self.tc.td:
202 self.tc.logger.error("Please unset PRSERV_HOST in order to run oe-selftest")
203 raise OEQAPreRun
204
205 if "SANITY_TESTED_DISTROS" in self.tc.td:
206 self.tc.logger.error("Please unset SANITY_TESTED_DISTROS in order to run oe-selftest")
207 raise OEQAPreRun
208
209 _add_layer_libs()
210
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800211 self.tc.logger.info("Running bitbake -e to test the configuration is valid/parsable")
212 runCmd("bitbake -e")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500213
Brad Bishopf86d0552018-12-04 14:18:15 -0800214 def get_json_result_dir(self, args):
215 json_result_dir = os.path.join(self.tc.td["LOG_DIR"], 'oeqa')
216 if "OEQA_JSON_RESULT_DIR" in self.tc.td:
217 json_result_dir = self.tc.td["OEQA_JSON_RESULT_DIR"]
218
219 return json_result_dir
220
221 def get_configuration(self, args):
222 import platform
223 from oeqa.utils.metadata import metadata_from_bb
224 metadata = metadata_from_bb()
225 configuration = {'TEST_TYPE': 'oeselftest',
226 'STARTTIME': args.test_start_time,
227 'MACHINE': self.tc.td["MACHINE"],
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800228 'HOST_DISTRO': oe.lsb.distro_identifier().replace(' ', '-'),
Brad Bishopf86d0552018-12-04 14:18:15 -0800229 'HOST_NAME': metadata['hostname'],
230 'LAYERS': metadata['layers']}
231 return configuration
232
233 def get_result_id(self, configuration):
234 return '%s_%s_%s_%s' % (configuration['TEST_TYPE'], configuration['HOST_DISTRO'], configuration['MACHINE'], configuration['STARTTIME'])
235
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500236 def _internal_run(self, logger, args):
237 self.module_paths = self._get_cases_paths(
238 self.tc_kwargs['init']['td']['BBPATH'].split(':'))
239
240 self.tc = self._context_class(**self.tc_kwargs['init'])
241 try:
242 self.tc.loadTests(self.module_paths, **self.tc_kwargs['load'])
243 except OEQATestNotFound as ex:
244 logger.error(ex)
245 sys.exit(1)
246
247 if args.list_tests:
248 rc = self.tc.listTests(args.list_tests, **self.tc_kwargs['list'])
249 else:
250 self._pre_run()
251 rc = self.tc.runTests(**self.tc_kwargs['run'])
Brad Bishopf86d0552018-12-04 14:18:15 -0800252 configuration = self.get_configuration(args)
253 rc.logDetails(self.get_json_result_dir(args),
254 configuration,
255 self.get_result_id(configuration))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500256 rc.logSummary(self.name)
257
258 return rc
259
260 def _signal_clean_handler(self, signum, frame):
261 sys.exit(1)
262
263 def run(self, logger, args):
264 self._process_args(logger, args)
265
266 signal.signal(signal.SIGTERM, self._signal_clean_handler)
267
268 rc = None
269 try:
270 if args.machine:
271 logger.info('Custom machine mode enabled. MACHINE set to %s' %
272 args.machine)
273
274 if args.machine == 'all':
275 results = []
276 for m in self.tc_kwargs['init']['machines']:
277 self.tc_kwargs['run']['machine'] = m
278 results.append(self._internal_run(logger, args))
279
280 # XXX: the oe-selftest script only needs to know if one
281 # machine run fails
282 for r in results:
283 rc = r
284 if not r.wasSuccessful():
285 break
286
287 else:
288 self.tc_kwargs['run']['machine'] = args.machine
289 return self._internal_run(logger, args)
290
291 else:
292 self.tc_kwargs['run']['machine'] = args.machine
293 rc = self._internal_run(logger, args)
294 finally:
295 config_paths = self.tc_kwargs['init']['config_paths']
296 if os.path.exists(config_paths['localconf_backup']):
297 copyfile(config_paths['localconf_backup'],
298 config_paths['localconf'])
299 os.remove(config_paths['localconf_backup'])
300
301 if os.path.exists(config_paths['bblayers_backup']):
302 copyfile(config_paths['bblayers_backup'],
303 config_paths['bblayers'])
304 os.remove(config_paths['bblayers_backup'])
305
306 if os.path.exists(config_paths['localconf_class_backup']):
307 os.remove(config_paths['localconf_class_backup'])
308 if os.path.exists(config_paths['bblayers_class_backup']):
309 os.remove(config_paths['bblayers_class_backup'])
310
311 output_link = os.path.join(os.path.dirname(args.output_log),
312 "%s-results.log" % self.name)
Brad Bishopf86d0552018-12-04 14:18:15 -0800313 if os.path.lexists(output_link):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500314 os.remove(output_link)
315 os.symlink(args.output_log, output_link)
316
317 return rc
318
319_executor_class = OESelftestTestContextExecutor